mirror of
https://github.com/golang/go.git
synced 2026-01-30 15:42:04 +03:00
Compare commits
59 Commits
dev.typepa
...
go1.17.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de690c2ff8 | ||
|
|
48d948963c | ||
|
|
65633fee16 | ||
|
|
e46abcb816 | ||
|
|
61317ef99e | ||
|
|
0f2d0d0694 | ||
|
|
759a9211d4 | ||
|
|
01779135c0 | ||
|
|
66007e5cfc | ||
|
|
3c50f27391 | ||
|
|
ab175939e2 | ||
|
|
f0ee7c6f96 | ||
|
|
b7651e5046 | ||
|
|
4eaf0b7a58 | ||
|
|
4536558f16 | ||
|
|
e347c89598 | ||
|
|
1c05b9b024 | ||
|
|
364f15ff9f | ||
|
|
b954f58e9d | ||
|
|
f1935e2c43 | ||
|
|
f58c78a577 | ||
|
|
b212ba6829 | ||
|
|
f9cb33c7c9 | ||
|
|
4a842985bf | ||
|
|
f6f024f120 | ||
|
|
18b970277e | ||
|
|
91aa2f190a | ||
|
|
8bdb0b235a | ||
|
|
3a03ddf735 | ||
|
|
644555d34e | ||
|
|
11b64b428b | ||
|
|
2ac3bdf378 | ||
|
|
4925e0766f | ||
|
|
b18ba59aaf | ||
|
|
04242ac88f | ||
|
|
c5c1d069da | ||
|
|
abc4f092ac | ||
|
|
e79c297fa8 | ||
|
|
21a4e67ad5 | ||
|
|
328cf2e8b2 | ||
|
|
fcce86c4cf | ||
|
|
36c171763e | ||
|
|
678b07d5e5 | ||
|
|
14c9b1e00b | ||
|
|
c35f8a37d9 | ||
|
|
47a57bc4f0 | ||
|
|
2d97a87287 | ||
|
|
3969694203 | ||
|
|
1dd24caf08 | ||
|
|
ec5170397c | ||
|
|
fdd6dfd507 | ||
|
|
f7b9470992 | ||
|
|
4397d66bdd | ||
|
|
eb5a7b5050 | ||
|
|
72ab3ff68b | ||
|
|
c3ccb77d1e | ||
|
|
c3b47cb598 | ||
|
|
ddfd72f7d1 | ||
|
|
d6f4d9a2be |
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.17
|
||||
parent-branch: master
|
||||
|
||||
@@ -753,9 +753,9 @@ func Foo() bool {
|
||||
|
||||
<p><!-- CL 311572 -->
|
||||
The new
|
||||
<a href="/pkg/database/sql/#NullInt16"><code>NullInt16</code></a>
|
||||
and
|
||||
<a href="/pkg/database/sql/#NullByte"><code>NullByte</code></a>
|
||||
<a href="/pkg/database/sql/#NullInt16"><code>NullInt16</code></a>
|
||||
and
|
||||
<a href="/pkg/database/sql/#NullByte"><code>NullByte</code></a>
|
||||
structs represent the int16 and byte values that may be null. These can be used as
|
||||
destinations of the <a href="/pkg/database/sql/#Scan"><code>Scan</code></a> method,
|
||||
similar to NullString.
|
||||
@@ -1205,11 +1205,11 @@ func Foo() bool {
|
||||
|
||||
<p><!-- CL 300996 -->
|
||||
The package now accepts comma "," as a separator for fractional seconds when parsing and formatting time.
|
||||
The following time formats are now accepted:
|
||||
For example, the following time layouts are now accepted:
|
||||
<ul>
|
||||
<li>2006-01-02 14:06:03,999999999 -0700 MST</li>
|
||||
<li>Mon Jan _2 14:06:03,120007 2006</li>
|
||||
<li>Mon Jan 2 14:06:03,120007 2006</li>
|
||||
<li>2006-01-02 15:04:05,999999999 -0700 MST</li>
|
||||
<li>Mon Jan _2 15:04:05,000000 2006</li>
|
||||
<li>Monday, January 2 15:04:05,000 2006</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ func TestIssue25756(t *testing.T) {
|
||||
|
||||
// Test with main using -buildmode=pie with plugin for issue #43228
|
||||
func TestIssue25756pie(t *testing.T) {
|
||||
if os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-11_0-toothrot" {
|
||||
if os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-11_0-toothrot" || os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-12_0-toothrot" {
|
||||
t.Skip("broken on darwin/arm64 builder in sharded mode; see issue 46239")
|
||||
}
|
||||
|
||||
|
||||
@@ -1070,3 +1070,11 @@ func TestIssue44031(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/b")
|
||||
goCmd(t, "run", "-linkshared", "./issue44031/main")
|
||||
}
|
||||
|
||||
// Test that we use a variable from shared libraries (which implement an
|
||||
// interface in shared libraries.). A weak reference is used in the itab
|
||||
// in main process. It can cause unreacheble panic. See issue 47873.
|
||||
func TestIssue47873(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue47837/a")
|
||||
goCmd(t, "run", "-linkshared", "./issue47837/main")
|
||||
}
|
||||
|
||||
19
misc/cgo/testshared/testdata/issue47837/a/a.go
vendored
Normal file
19
misc/cgo/testshared/testdata/issue47837/a/a.go
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2021 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 a
|
||||
|
||||
type A interface {
|
||||
M()
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func TheFuncWithArgA(a A) {
|
||||
a.M()
|
||||
}
|
||||
|
||||
type ImplA struct{}
|
||||
|
||||
//go:noinline
|
||||
func (A *ImplA) M() {}
|
||||
14
misc/cgo/testshared/testdata/issue47837/main/main.go
vendored
Normal file
14
misc/cgo/testshared/testdata/issue47837/main/main.go
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"testshared/issue47837/a"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var vara a.ImplA
|
||||
a.TheFuncWithArgA(&vara)
|
||||
}
|
||||
@@ -567,6 +567,13 @@
|
||||
offset += 8;
|
||||
});
|
||||
|
||||
// The linker guarantees global data starts from at least wasmMinDataAddr.
|
||||
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
|
||||
const wasmMinDataAddr = 4096 + 8192;
|
||||
if (offset >= wasmMinDataAddr) {
|
||||
throw new Error("total length of command line and environment variables exceeds limit");
|
||||
}
|
||||
|
||||
this._inst.exports.run(argc, argv);
|
||||
if (this.exited) {
|
||||
this._resolveExitPromise();
|
||||
|
||||
@@ -102,7 +102,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
|
||||
// indicate it contains up to 1 << 128 - 1 files. Since each file has a
|
||||
// header which will be _at least_ 30 bytes we can safely preallocate
|
||||
// if (data size / 30) >= end.directoryRecords.
|
||||
if (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
|
||||
if end.directorySize < uint64(size) && (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
|
||||
z.File = make([]*File, 0, end.directoryRecords)
|
||||
}
|
||||
z.Comment = end.comment
|
||||
@@ -741,6 +741,9 @@ func (r *Reader) initFileList() {
|
||||
for _, file := range r.File {
|
||||
isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
|
||||
name := toValidName(file.Name)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
||||
dirs[dir] = true
|
||||
}
|
||||
@@ -782,8 +785,11 @@ func fileEntryLess(x, y string) bool {
|
||||
func (r *Reader) Open(name string) (fs.File, error) {
|
||||
r.initFileList()
|
||||
|
||||
if !fs.ValidPath(name) {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
|
||||
}
|
||||
e := r.openLookup(name)
|
||||
if e == nil || !fs.ValidPath(name) {
|
||||
if e == nil {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
||||
}
|
||||
if e.isDir {
|
||||
@@ -797,7 +803,7 @@ func (r *Reader) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
func split(name string) (dir, elem string, isDir bool) {
|
||||
if name[len(name)-1] == '/' {
|
||||
if len(name) > 0 && name[len(name)-1] == '/' {
|
||||
isDir = true
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -1202,6 +1203,15 @@ func TestCVE202127919(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Error reading file: %v", err)
|
||||
}
|
||||
if len(r.File) != 1 {
|
||||
t.Fatalf("No entries in the file list")
|
||||
}
|
||||
if r.File[0].Name != "../test.txt" {
|
||||
t.Errorf("Unexpected entry name: %s", r.File[0].Name)
|
||||
}
|
||||
if _, err := r.File[0].Open(); err != nil {
|
||||
t.Errorf("Error opening file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadDataDescriptor(t *testing.T) {
|
||||
@@ -1384,3 +1394,139 @@ func TestCVE202133196(t *testing.T) {
|
||||
t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202139293(t *testing.T) {
|
||||
// directory size is so large, that the check in Reader.init
|
||||
// overflows when subtracting from the archive size, causing
|
||||
// the pre-allocation check to be bypassed.
|
||||
data := []byte{
|
||||
0x50, 0x4b, 0x06, 0x06, 0x05, 0x06, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b,
|
||||
0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b,
|
||||
0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0x50, 0xfe, 0x00, 0xff, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xff,
|
||||
}
|
||||
_, err := NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != ErrFormat {
|
||||
t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202141772(t *testing.T) {
|
||||
// Archive contains a file whose name is exclusively made up of '/', '\'
|
||||
// characters, or "../", "..\" paths, which would previously cause a panic.
|
||||
//
|
||||
// Length Method Size Cmpr Date Time CRC-32 Name
|
||||
// -------- ------ ------- ---- ---------- ----- -------- ----
|
||||
// 0 Stored 0 0% 08-05-2021 18:32 00000000 /
|
||||
// 0 Stored 0 0% 09-14-2021 12:59 00000000 //
|
||||
// 0 Stored 0 0% 09-14-2021 12:59 00000000 \
|
||||
// 11 Stored 11 0% 09-14-2021 13:04 0d4a1185 /test.txt
|
||||
// -------- ------- --- -------
|
||||
// 11 11 0% 4 files
|
||||
data := []byte{
|
||||
0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x08,
|
||||
0x00, 0x00, 0x06, 0x94, 0x05, 0x53, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x50,
|
||||
0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x50,
|
||||
0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x50, 0x4b,
|
||||
0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x91, 0x68, 0x2e, 0x53, 0x85, 0x11, 0x4a, 0x0d,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
|
||||
0x74, 0x2e, 0x74, 0x78, 0x74, 0x68, 0x65, 0x6c,
|
||||
0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
|
||||
0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x0a, 0x00,
|
||||
0x00, 0x08, 0x00, 0x00, 0x06, 0x94, 0x05, 0x53,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
|
||||
0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x50,
|
||||
0x4b, 0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x0a,
|
||||
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x18, 0x00, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x50, 0x4b, 0x01, 0x02, 0x3f,
|
||||
0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
|
||||
0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00,
|
||||
0x00, 0x5c, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x50, 0x4b,
|
||||
0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x91, 0x68, 0x2e, 0x53, 0x85, 0x11,
|
||||
0x4a, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00,
|
||||
0x00, 0x00, 0x09, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x5e, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
|
||||
0x74, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18,
|
||||
0x00, 0xa9, 0x80, 0x51, 0x01, 0x26, 0xa9, 0xd7,
|
||||
0x01, 0x31, 0xd1, 0x57, 0x01, 0x26, 0xa9, 0xd7,
|
||||
0x01, 0xdf, 0x48, 0x85, 0xf9, 0x25, 0xa9, 0xd7,
|
||||
0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x04, 0x00, 0x31, 0x01, 0x00,
|
||||
0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading the archive: %v", err)
|
||||
}
|
||||
entryNames := []string{`/`, `//`, `\`, `/test.txt`}
|
||||
var names []string
|
||||
for _, f := range r.File {
|
||||
names = append(names, f.Name)
|
||||
if _, err := f.Open(); err != nil {
|
||||
t.Errorf("Error opening %q: %v", f.Name, err)
|
||||
}
|
||||
if _, err := r.Open(f.Name); err == nil {
|
||||
t.Errorf("Opening %q with fs.FS API succeeded", f.Name)
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(names, entryNames) {
|
||||
t.Errorf("Unexpected file entries: %q", names)
|
||||
}
|
||||
if _, err := r.Open(""); err == nil {
|
||||
t.Errorf("Opening %q with fs.FS API succeeded", "")
|
||||
}
|
||||
if _, err := r.Open("test.txt"); err != nil {
|
||||
t.Errorf("Error opening %q with fs.FS API: %v", "test.txt", err)
|
||||
}
|
||||
dirEntries, err := fs.ReadDir(r, ".")
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading the root directory: %v", err)
|
||||
}
|
||||
if len(dirEntries) != 1 || dirEntries[0].Name() != "test.txt" {
|
||||
t.Errorf("Unexpected directory entries")
|
||||
for _, dirEntry := range dirEntries {
|
||||
_, err := r.Open(dirEntry.Name())
|
||||
t.Logf("%q (Open error: %v)", dirEntry.Name(), err)
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
info, err := dirEntries[0].Info()
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading info entry: %v", err)
|
||||
}
|
||||
if name := info.Name(); name != "test.txt" {
|
||||
t.Errorf("Inconsistent name in info entry: %v", name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,10 +495,11 @@ func transformSelect(sel *ir.SelectStmt) {
|
||||
if ncase.Comm != nil {
|
||||
n := ncase.Comm
|
||||
oselrecv2 := func(dst, recv ir.Node, def bool) {
|
||||
n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
n.Def = def
|
||||
n.SetTypecheck(1)
|
||||
ncase.Comm = n
|
||||
selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
selrecv.Def = def
|
||||
selrecv.SetTypecheck(1)
|
||||
selrecv.SetInit(n.Init())
|
||||
ncase.Comm = selrecv
|
||||
}
|
||||
switch n.Op() {
|
||||
case ir.OAS:
|
||||
|
||||
@@ -952,6 +952,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
|
||||
return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
|
||||
}
|
||||
eltRO := x.regWidth(elt)
|
||||
source.Type = t
|
||||
for i := int64(0); i < t.NumElem(); i++ {
|
||||
sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source)
|
||||
mem = x.storeArgOrLoad(pos, b, sel, mem, elt, storeOffset+i*elt.Width, loadRegOffset, storeRc.at(t, 0))
|
||||
@@ -985,6 +986,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
|
||||
return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
|
||||
}
|
||||
|
||||
source.Type = t
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
fld := t.Field(i)
|
||||
sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source)
|
||||
|
||||
@@ -78,7 +78,11 @@ func fuseBranchRedirect(f *Func) bool {
|
||||
if v.Op != OpPhi {
|
||||
continue
|
||||
}
|
||||
v.RemoveArg(k)
|
||||
n := len(v.Args)
|
||||
v.Args[k].Uses--
|
||||
v.Args[k] = v.Args[n-1]
|
||||
v.Args[n-1] = nil
|
||||
v.Args = v.Args[:n-1]
|
||||
phielimValue(v)
|
||||
}
|
||||
// Fix up child to have one more predecessor.
|
||||
|
||||
@@ -497,9 +497,9 @@
|
||||
(XOR x (MOVWconst [c])) => (XORconst [c] x)
|
||||
(BIC x (MOVWconst [c])) => (BICconst [c] x)
|
||||
|
||||
(SLL x (MOVWconst [c])) => (SLLconst x [c&31]) // Note: I don't think we ever generate bad constant shifts (i.e. c>=32)
|
||||
(SRL x (MOVWconst [c])) => (SRLconst x [c&31])
|
||||
(SRA x (MOVWconst [c])) => (SRAconst x [c&31])
|
||||
(SLL x (MOVWconst [c])) && 0 <= c && c < 32 => (SLLconst x [c])
|
||||
(SRL x (MOVWconst [c])) && 0 <= c && c < 32 => (SRLconst x [c])
|
||||
(SRA x (MOVWconst [c])) && 0 <= c && c < 32 => (SRAconst x [c])
|
||||
|
||||
(CMP x (MOVWconst [c])) => (CMPconst [c] x)
|
||||
(CMP (MOVWconst [c]) x) => (InvertFlags (CMPconst [c] x))
|
||||
@@ -1072,60 +1072,60 @@
|
||||
(CMNshiftRL x (MOVWconst [c]) [d]) => (CMNconst x [int32(uint32(c)>>uint64(d))])
|
||||
(CMNshiftRA x (MOVWconst [c]) [d]) => (CMNconst x [c>>uint64(d)])
|
||||
|
||||
(ADDshiftLLreg x y (MOVWconst [c])) => (ADDshiftLL x y [c])
|
||||
(ADDshiftRLreg x y (MOVWconst [c])) => (ADDshiftRL x y [c])
|
||||
(ADDshiftRAreg x y (MOVWconst [c])) => (ADDshiftRA x y [c])
|
||||
(ADCshiftLLreg x y (MOVWconst [c]) flags) => (ADCshiftLL x y [c] flags)
|
||||
(ADCshiftRLreg x y (MOVWconst [c]) flags) => (ADCshiftRL x y [c] flags)
|
||||
(ADCshiftRAreg x y (MOVWconst [c]) flags) => (ADCshiftRA x y [c] flags)
|
||||
(ADDSshiftLLreg x y (MOVWconst [c])) => (ADDSshiftLL x y [c])
|
||||
(ADDSshiftRLreg x y (MOVWconst [c])) => (ADDSshiftRL x y [c])
|
||||
(ADDSshiftRAreg x y (MOVWconst [c])) => (ADDSshiftRA x y [c])
|
||||
(SUBshiftLLreg x y (MOVWconst [c])) => (SUBshiftLL x y [c])
|
||||
(SUBshiftRLreg x y (MOVWconst [c])) => (SUBshiftRL x y [c])
|
||||
(SUBshiftRAreg x y (MOVWconst [c])) => (SUBshiftRA x y [c])
|
||||
(SBCshiftLLreg x y (MOVWconst [c]) flags) => (SBCshiftLL x y [c] flags)
|
||||
(SBCshiftRLreg x y (MOVWconst [c]) flags) => (SBCshiftRL x y [c] flags)
|
||||
(SBCshiftRAreg x y (MOVWconst [c]) flags) => (SBCshiftRA x y [c] flags)
|
||||
(SUBSshiftLLreg x y (MOVWconst [c])) => (SUBSshiftLL x y [c])
|
||||
(SUBSshiftRLreg x y (MOVWconst [c])) => (SUBSshiftRL x y [c])
|
||||
(SUBSshiftRAreg x y (MOVWconst [c])) => (SUBSshiftRA x y [c])
|
||||
(RSBshiftLLreg x y (MOVWconst [c])) => (RSBshiftLL x y [c])
|
||||
(RSBshiftRLreg x y (MOVWconst [c])) => (RSBshiftRL x y [c])
|
||||
(RSBshiftRAreg x y (MOVWconst [c])) => (RSBshiftRA x y [c])
|
||||
(RSCshiftLLreg x y (MOVWconst [c]) flags) => (RSCshiftLL x y [c] flags)
|
||||
(RSCshiftRLreg x y (MOVWconst [c]) flags) => (RSCshiftRL x y [c] flags)
|
||||
(RSCshiftRAreg x y (MOVWconst [c]) flags) => (RSCshiftRA x y [c] flags)
|
||||
(RSBSshiftLLreg x y (MOVWconst [c])) => (RSBSshiftLL x y [c])
|
||||
(RSBSshiftRLreg x y (MOVWconst [c])) => (RSBSshiftRL x y [c])
|
||||
(RSBSshiftRAreg x y (MOVWconst [c])) => (RSBSshiftRA x y [c])
|
||||
(ANDshiftLLreg x y (MOVWconst [c])) => (ANDshiftLL x y [c])
|
||||
(ANDshiftRLreg x y (MOVWconst [c])) => (ANDshiftRL x y [c])
|
||||
(ANDshiftRAreg x y (MOVWconst [c])) => (ANDshiftRA x y [c])
|
||||
(ORshiftLLreg x y (MOVWconst [c])) => (ORshiftLL x y [c])
|
||||
(ORshiftRLreg x y (MOVWconst [c])) => (ORshiftRL x y [c])
|
||||
(ORshiftRAreg x y (MOVWconst [c])) => (ORshiftRA x y [c])
|
||||
(XORshiftLLreg x y (MOVWconst [c])) => (XORshiftLL x y [c])
|
||||
(XORshiftRLreg x y (MOVWconst [c])) => (XORshiftRL x y [c])
|
||||
(XORshiftRAreg x y (MOVWconst [c])) => (XORshiftRA x y [c])
|
||||
(BICshiftLLreg x y (MOVWconst [c])) => (BICshiftLL x y [c])
|
||||
(BICshiftRLreg x y (MOVWconst [c])) => (BICshiftRL x y [c])
|
||||
(BICshiftRAreg x y (MOVWconst [c])) => (BICshiftRA x y [c])
|
||||
(MVNshiftLLreg x (MOVWconst [c])) => (MVNshiftLL x [c])
|
||||
(MVNshiftRLreg x (MOVWconst [c])) => (MVNshiftRL x [c])
|
||||
(MVNshiftRAreg x (MOVWconst [c])) => (MVNshiftRA x [c])
|
||||
(CMPshiftLLreg x y (MOVWconst [c])) => (CMPshiftLL x y [c])
|
||||
(CMPshiftRLreg x y (MOVWconst [c])) => (CMPshiftRL x y [c])
|
||||
(CMPshiftRAreg x y (MOVWconst [c])) => (CMPshiftRA x y [c])
|
||||
(TSTshiftLLreg x y (MOVWconst [c])) => (TSTshiftLL x y [c])
|
||||
(TSTshiftRLreg x y (MOVWconst [c])) => (TSTshiftRL x y [c])
|
||||
(TSTshiftRAreg x y (MOVWconst [c])) => (TSTshiftRA x y [c])
|
||||
(TEQshiftLLreg x y (MOVWconst [c])) => (TEQshiftLL x y [c])
|
||||
(TEQshiftRLreg x y (MOVWconst [c])) => (TEQshiftRL x y [c])
|
||||
(TEQshiftRAreg x y (MOVWconst [c])) => (TEQshiftRA x y [c])
|
||||
(CMNshiftLLreg x y (MOVWconst [c])) => (CMNshiftLL x y [c])
|
||||
(CMNshiftRLreg x y (MOVWconst [c])) => (CMNshiftRL x y [c])
|
||||
(CMNshiftRAreg x y (MOVWconst [c])) => (CMNshiftRA x y [c])
|
||||
(ADDshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftLL x y [c])
|
||||
(ADDshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftRL x y [c])
|
||||
(ADDshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftRA x y [c])
|
||||
(ADCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftLL x y [c] flags)
|
||||
(ADCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftRL x y [c] flags)
|
||||
(ADCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftRA x y [c] flags)
|
||||
(ADDSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftLL x y [c])
|
||||
(ADDSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftRL x y [c])
|
||||
(ADDSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftRA x y [c])
|
||||
(SUBshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftLL x y [c])
|
||||
(SUBshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftRL x y [c])
|
||||
(SUBshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftRA x y [c])
|
||||
(SBCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftLL x y [c] flags)
|
||||
(SBCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftRL x y [c] flags)
|
||||
(SBCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftRA x y [c] flags)
|
||||
(SUBSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftLL x y [c])
|
||||
(SUBSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftRL x y [c])
|
||||
(SUBSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftRA x y [c])
|
||||
(RSBshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftLL x y [c])
|
||||
(RSBshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftRL x y [c])
|
||||
(RSBshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftRA x y [c])
|
||||
(RSCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftLL x y [c] flags)
|
||||
(RSCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftRL x y [c] flags)
|
||||
(RSCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftRA x y [c] flags)
|
||||
(RSBSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftLL x y [c])
|
||||
(RSBSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftRL x y [c])
|
||||
(RSBSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftRA x y [c])
|
||||
(ANDshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftLL x y [c])
|
||||
(ANDshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftRL x y [c])
|
||||
(ANDshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftRA x y [c])
|
||||
(ORshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftLL x y [c])
|
||||
(ORshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftRL x y [c])
|
||||
(ORshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftRA x y [c])
|
||||
(XORshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftLL x y [c])
|
||||
(XORshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftRL x y [c])
|
||||
(XORshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftRA x y [c])
|
||||
(BICshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftLL x y [c])
|
||||
(BICshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftRL x y [c])
|
||||
(BICshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftRA x y [c])
|
||||
(MVNshiftLLreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftLL x [c])
|
||||
(MVNshiftRLreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftRL x [c])
|
||||
(MVNshiftRAreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftRA x [c])
|
||||
(CMPshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftLL x y [c])
|
||||
(CMPshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftRL x y [c])
|
||||
(CMPshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftRA x y [c])
|
||||
(TSTshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftLL x y [c])
|
||||
(TSTshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftRL x y [c])
|
||||
(TSTshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftRA x y [c])
|
||||
(TEQshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftLL x y [c])
|
||||
(TEQshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftRL x y [c])
|
||||
(TEQshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftRA x y [c])
|
||||
(CMNshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftLL x y [c])
|
||||
(CMNshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftRL x y [c])
|
||||
(CMNshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftRA x y [c])
|
||||
|
||||
// Generate rotates
|
||||
(ADDshiftLL [c] (SRLconst x [32-c]) x) => (SRRconst [32-c] x)
|
||||
@@ -1237,24 +1237,24 @@
|
||||
(AND x (MVN y)) => (BIC x y)
|
||||
|
||||
// simplification with *shift ops
|
||||
(SUBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(SUBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(SUBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(RSBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(RSBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(RSBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
|
||||
(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
|
||||
(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
|
||||
(ORshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
|
||||
(ORshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
|
||||
(ORshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
|
||||
(XORshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(XORshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(XORshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(BICshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(BICshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(BICshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(SUBshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(SUBshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(SUBshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(RSBshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(RSBshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(RSBshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(ANDshiftLL y:(SLLconst x [c]) x [c]) => y
|
||||
(ANDshiftRL y:(SRLconst x [c]) x [c]) => y
|
||||
(ANDshiftRA y:(SRAconst x [c]) x [c]) => y
|
||||
(ORshiftLL y:(SLLconst x [c]) x [c]) => y
|
||||
(ORshiftRL y:(SRLconst x [c]) x [c]) => y
|
||||
(ORshiftRA y:(SRAconst x [c]) x [c]) => y
|
||||
(XORshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(XORshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(XORshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(BICshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(BICshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(BICshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(AND x (MVNshiftLL y [c])) => (BICshiftLL x y [c])
|
||||
(AND x (MVNshiftRL y [c])) => (BICshiftRL x y [c])
|
||||
(AND x (MVNshiftRA y [c])) => (BICshiftRA x y [c])
|
||||
|
||||
@@ -1698,27 +1698,27 @@
|
||||
(TSTshiftRA x (MOVDconst [c]) [d]) => (TSTconst x [c>>uint64(d)])
|
||||
|
||||
// simplification with *shift ops
|
||||
(SUBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(SUBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(SUBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
|
||||
(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
|
||||
(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
|
||||
(ORshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
|
||||
(ORshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
|
||||
(ORshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
|
||||
(XORshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(XORshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(XORshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(BICshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(BICshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(BICshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(EONshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(EONshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(EONshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(ORNshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(ORNshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(ORNshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(SUBshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(SUBshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(SUBshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(ANDshiftLL y:(SLLconst x [c]) x [c]) => y
|
||||
(ANDshiftRL y:(SRLconst x [c]) x [c]) => y
|
||||
(ANDshiftRA y:(SRAconst x [c]) x [c]) => y
|
||||
(ORshiftLL y:(SLLconst x [c]) x [c]) => y
|
||||
(ORshiftRL y:(SRLconst x [c]) x [c]) => y
|
||||
(ORshiftRA y:(SRAconst x [c]) x [c]) => y
|
||||
(XORshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(XORshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(XORshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(BICshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(BICshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(BICshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(EONshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(EONshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(EONshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(ORNshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(ORNshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(ORNshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
|
||||
// Generate rotates with const shift
|
||||
(ADDshiftLL [c] (SRLconst x [64-c]) x) => (RORconst [64-c] x)
|
||||
|
||||
@@ -228,14 +228,15 @@ func init() {
|
||||
|
||||
// shifts
|
||||
{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 256
|
||||
{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt
|
||||
{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, 0 <= auxInt < 32
|
||||
{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> arg1, unsigned, shift amount is mod 256
|
||||
{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned
|
||||
{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned, 0 <= auxInt < 32
|
||||
{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> arg1, signed, shift amount is mod 256
|
||||
{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed
|
||||
{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, 0 <= auxInt < 32
|
||||
{name: "SRR", argLength: 2, reg: gp21}, // arg0 right rotate by arg1 bits
|
||||
{name: "SRRconst", argLength: 1, reg: gp11, aux: "Int32"}, // arg0 right rotate by auxInt bits
|
||||
{name: "SRRconst", argLength: 1, reg: gp11, aux: "Int32"}, // arg0 right rotate by auxInt bits, 0 <= auxInt < 32
|
||||
|
||||
// auxInt for all of these satisfy 0 <= auxInt < 32
|
||||
{name: "ADDshiftLL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1<<auxInt
|
||||
{name: "ADDshiftRL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, unsigned shift
|
||||
{name: "ADDshiftRA", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, signed shift
|
||||
|
||||
@@ -106,7 +106,7 @@ var genericOps = []opData{
|
||||
|
||||
// For shifts, AxB means the shifted value has A bits and the shift amount has B bits.
|
||||
// Shift amounts are considered unsigned.
|
||||
// If arg1 is known to be less than the number of bits in arg0,
|
||||
// If arg1 is known to be nonnegative and less than the number of bits in arg0,
|
||||
// then auxInt may be set to 1.
|
||||
// This enables better code generation on some platforms.
|
||||
{name: "Lsh8x8", argLength: 2, aux: "Bool"}, // arg0 << arg1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2265,18 +2265,16 @@ func rewriteValueARM64_OpARM64ANDshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ANDshiftLL x y:(SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ANDshiftLL y:(SLLconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SLLconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -2319,18 +2317,16 @@ func rewriteValueARM64_OpARM64ANDshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ANDshiftRA x y:(SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ANDshiftRA y:(SRAconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SRAconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -2373,18 +2369,16 @@ func rewriteValueARM64_OpARM64ANDshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ANDshiftRL x y:(SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ANDshiftRL y:(SRLconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SRLconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -2495,17 +2489,15 @@ func rewriteValueARM64_OpARM64BICshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (BICshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (BICshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -2531,17 +2523,15 @@ func rewriteValueARM64_OpARM64BICshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (BICshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (BICshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -2567,17 +2557,15 @@ func rewriteValueARM64_OpARM64BICshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (BICshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (BICshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -3945,17 +3933,15 @@ func rewriteValueARM64_OpARM64EONshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (EONshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (EONshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -3981,17 +3967,15 @@ func rewriteValueARM64_OpARM64EONshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (EONshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (EONshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -4017,17 +4001,15 @@ func rewriteValueARM64_OpARM64EONshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (EONshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (EONshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -17819,17 +17801,15 @@ func rewriteValueARM64_OpARM64ORNshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORNshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORNshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -17855,17 +17835,15 @@ func rewriteValueARM64_OpARM64ORNshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORNshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORNshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -17891,17 +17869,15 @@ func rewriteValueARM64_OpARM64ORNshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORNshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORNshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -18014,18 +17990,16 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORshiftLL x y:(SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORshiftLL y:(SLLconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SLLconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -19694,18 +19668,16 @@ func rewriteValueARM64_OpARM64ORshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORshiftRA x y:(SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORshiftRA y:(SRAconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SRAconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -19748,18 +19720,16 @@ func rewriteValueARM64_OpARM64ORshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORshiftRL x y:(SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORshiftRL y:(SRLconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SRLconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -20836,17 +20806,15 @@ func rewriteValueARM64_OpARM64SUBshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUBshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (SUBshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -20872,17 +20840,15 @@ func rewriteValueARM64_OpARM64SUBshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUBshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (SUBshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -20908,17 +20874,15 @@ func rewriteValueARM64_OpARM64SUBshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUBshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (SUBshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -22007,17 +21971,15 @@ func rewriteValueARM64_OpARM64XORshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (XORshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (XORshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -22219,17 +22181,15 @@ func rewriteValueARM64_OpARM64XORshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (XORshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (XORshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -22273,17 +22233,15 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (XORshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (XORshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
|
||||
@@ -2387,6 +2387,175 @@ func (s *state) ssaShiftOp(op ir.Op, t *types.Type, u *types.Type) ssa.Op {
|
||||
return x
|
||||
}
|
||||
|
||||
func (s *state) conv(n ir.Node, v *ssa.Value, ft, tt *types.Type) *ssa.Value {
|
||||
if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
|
||||
// Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
|
||||
return s.newValue1(ssa.OpCopy, tt, v)
|
||||
}
|
||||
if ft.IsInteger() && tt.IsInteger() {
|
||||
var op ssa.Op
|
||||
if tt.Size() == ft.Size() {
|
||||
op = ssa.OpCopy
|
||||
} else if tt.Size() < ft.Size() {
|
||||
// truncation
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 21:
|
||||
op = ssa.OpTrunc16to8
|
||||
case 41:
|
||||
op = ssa.OpTrunc32to8
|
||||
case 42:
|
||||
op = ssa.OpTrunc32to16
|
||||
case 81:
|
||||
op = ssa.OpTrunc64to8
|
||||
case 82:
|
||||
op = ssa.OpTrunc64to16
|
||||
case 84:
|
||||
op = ssa.OpTrunc64to32
|
||||
default:
|
||||
s.Fatalf("weird integer truncation %v -> %v", ft, tt)
|
||||
}
|
||||
} else if ft.IsSigned() {
|
||||
// sign extension
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 12:
|
||||
op = ssa.OpSignExt8to16
|
||||
case 14:
|
||||
op = ssa.OpSignExt8to32
|
||||
case 18:
|
||||
op = ssa.OpSignExt8to64
|
||||
case 24:
|
||||
op = ssa.OpSignExt16to32
|
||||
case 28:
|
||||
op = ssa.OpSignExt16to64
|
||||
case 48:
|
||||
op = ssa.OpSignExt32to64
|
||||
default:
|
||||
s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
|
||||
}
|
||||
} else {
|
||||
// zero extension
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 12:
|
||||
op = ssa.OpZeroExt8to16
|
||||
case 14:
|
||||
op = ssa.OpZeroExt8to32
|
||||
case 18:
|
||||
op = ssa.OpZeroExt8to64
|
||||
case 24:
|
||||
op = ssa.OpZeroExt16to32
|
||||
case 28:
|
||||
op = ssa.OpZeroExt16to64
|
||||
case 48:
|
||||
op = ssa.OpZeroExt32to64
|
||||
default:
|
||||
s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
|
||||
}
|
||||
}
|
||||
return s.newValue1(op, tt, v)
|
||||
}
|
||||
|
||||
if ft.IsFloat() || tt.IsFloat() {
|
||||
conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
|
||||
if s.config.RegSize == 4 && Arch.LinkArch.Family != sys.MIPS && !s.softFloat {
|
||||
if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
|
||||
conv = conv1
|
||||
}
|
||||
}
|
||||
if Arch.LinkArch.Family == sys.ARM64 || Arch.LinkArch.Family == sys.Wasm || Arch.LinkArch.Family == sys.S390X || s.softFloat {
|
||||
if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
|
||||
conv = conv1
|
||||
}
|
||||
}
|
||||
|
||||
if Arch.LinkArch.Family == sys.MIPS && !s.softFloat {
|
||||
if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
|
||||
// tt is float32 or float64, and ft is also unsigned
|
||||
if tt.Size() == 4 {
|
||||
return s.uint32Tofloat32(n, v, ft, tt)
|
||||
}
|
||||
if tt.Size() == 8 {
|
||||
return s.uint32Tofloat64(n, v, ft, tt)
|
||||
}
|
||||
} else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
|
||||
// ft is float32 or float64, and tt is unsigned integer
|
||||
if ft.Size() == 4 {
|
||||
return s.float32ToUint32(n, v, ft, tt)
|
||||
}
|
||||
if ft.Size() == 8 {
|
||||
return s.float64ToUint32(n, v, ft, tt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
s.Fatalf("weird float conversion %v -> %v", ft, tt)
|
||||
}
|
||||
op1, op2, it := conv.op1, conv.op2, conv.intermediateType
|
||||
|
||||
if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
|
||||
// normal case, not tripping over unsigned 64
|
||||
if op1 == ssa.OpCopy {
|
||||
if op2 == ssa.OpCopy {
|
||||
return v
|
||||
}
|
||||
return s.newValueOrSfCall1(op2, tt, v)
|
||||
}
|
||||
if op2 == ssa.OpCopy {
|
||||
return s.newValueOrSfCall1(op1, tt, v)
|
||||
}
|
||||
return s.newValueOrSfCall1(op2, tt, s.newValueOrSfCall1(op1, types.Types[it], v))
|
||||
}
|
||||
// Tricky 64-bit unsigned cases.
|
||||
if ft.IsInteger() {
|
||||
// tt is float32 or float64, and ft is also unsigned
|
||||
if tt.Size() == 4 {
|
||||
return s.uint64Tofloat32(n, v, ft, tt)
|
||||
}
|
||||
if tt.Size() == 8 {
|
||||
return s.uint64Tofloat64(n, v, ft, tt)
|
||||
}
|
||||
s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
|
||||
}
|
||||
// ft is float32 or float64, and tt is unsigned integer
|
||||
if ft.Size() == 4 {
|
||||
return s.float32ToUint64(n, v, ft, tt)
|
||||
}
|
||||
if ft.Size() == 8 {
|
||||
return s.float64ToUint64(n, v, ft, tt)
|
||||
}
|
||||
s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
|
||||
return nil
|
||||
}
|
||||
|
||||
if ft.IsComplex() && tt.IsComplex() {
|
||||
var op ssa.Op
|
||||
if ft.Size() == tt.Size() {
|
||||
switch ft.Size() {
|
||||
case 8:
|
||||
op = ssa.OpRound32F
|
||||
case 16:
|
||||
op = ssa.OpRound64F
|
||||
default:
|
||||
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
|
||||
}
|
||||
} else if ft.Size() == 8 && tt.Size() == 16 {
|
||||
op = ssa.OpCvt32Fto64F
|
||||
} else if ft.Size() == 16 && tt.Size() == 8 {
|
||||
op = ssa.OpCvt64Fto32F
|
||||
} else {
|
||||
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
|
||||
}
|
||||
ftp := types.FloatForComplex(ft)
|
||||
ttp := types.FloatForComplex(tt)
|
||||
return s.newValue2(ssa.OpComplexMake, tt,
|
||||
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, v)),
|
||||
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, v)))
|
||||
}
|
||||
|
||||
s.Fatalf("unhandled OCONV %s -> %s", ft.Kind(), tt.Kind())
|
||||
return nil
|
||||
}
|
||||
|
||||
// expr converts the expression n to ssa, adds it to s and returns the ssa result.
|
||||
func (s *state) expr(n ir.Node) *ssa.Value {
|
||||
if ir.HasUniquePos(n) {
|
||||
@@ -2574,174 +2743,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
|
||||
case ir.OCONV:
|
||||
n := n.(*ir.ConvExpr)
|
||||
x := s.expr(n.X)
|
||||
ft := n.X.Type() // from type
|
||||
tt := n.Type() // to type
|
||||
if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
|
||||
// Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
|
||||
return s.newValue1(ssa.OpCopy, n.Type(), x)
|
||||
}
|
||||
if ft.IsInteger() && tt.IsInteger() {
|
||||
var op ssa.Op
|
||||
if tt.Size() == ft.Size() {
|
||||
op = ssa.OpCopy
|
||||
} else if tt.Size() < ft.Size() {
|
||||
// truncation
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 21:
|
||||
op = ssa.OpTrunc16to8
|
||||
case 41:
|
||||
op = ssa.OpTrunc32to8
|
||||
case 42:
|
||||
op = ssa.OpTrunc32to16
|
||||
case 81:
|
||||
op = ssa.OpTrunc64to8
|
||||
case 82:
|
||||
op = ssa.OpTrunc64to16
|
||||
case 84:
|
||||
op = ssa.OpTrunc64to32
|
||||
default:
|
||||
s.Fatalf("weird integer truncation %v -> %v", ft, tt)
|
||||
}
|
||||
} else if ft.IsSigned() {
|
||||
// sign extension
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 12:
|
||||
op = ssa.OpSignExt8to16
|
||||
case 14:
|
||||
op = ssa.OpSignExt8to32
|
||||
case 18:
|
||||
op = ssa.OpSignExt8to64
|
||||
case 24:
|
||||
op = ssa.OpSignExt16to32
|
||||
case 28:
|
||||
op = ssa.OpSignExt16to64
|
||||
case 48:
|
||||
op = ssa.OpSignExt32to64
|
||||
default:
|
||||
s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
|
||||
}
|
||||
} else {
|
||||
// zero extension
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 12:
|
||||
op = ssa.OpZeroExt8to16
|
||||
case 14:
|
||||
op = ssa.OpZeroExt8to32
|
||||
case 18:
|
||||
op = ssa.OpZeroExt8to64
|
||||
case 24:
|
||||
op = ssa.OpZeroExt16to32
|
||||
case 28:
|
||||
op = ssa.OpZeroExt16to64
|
||||
case 48:
|
||||
op = ssa.OpZeroExt32to64
|
||||
default:
|
||||
s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
|
||||
}
|
||||
}
|
||||
return s.newValue1(op, n.Type(), x)
|
||||
}
|
||||
|
||||
if ft.IsFloat() || tt.IsFloat() {
|
||||
conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
|
||||
if s.config.RegSize == 4 && Arch.LinkArch.Family != sys.MIPS && !s.softFloat {
|
||||
if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
|
||||
conv = conv1
|
||||
}
|
||||
}
|
||||
if Arch.LinkArch.Family == sys.ARM64 || Arch.LinkArch.Family == sys.Wasm || Arch.LinkArch.Family == sys.S390X || s.softFloat {
|
||||
if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
|
||||
conv = conv1
|
||||
}
|
||||
}
|
||||
|
||||
if Arch.LinkArch.Family == sys.MIPS && !s.softFloat {
|
||||
if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
|
||||
// tt is float32 or float64, and ft is also unsigned
|
||||
if tt.Size() == 4 {
|
||||
return s.uint32Tofloat32(n, x, ft, tt)
|
||||
}
|
||||
if tt.Size() == 8 {
|
||||
return s.uint32Tofloat64(n, x, ft, tt)
|
||||
}
|
||||
} else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
|
||||
// ft is float32 or float64, and tt is unsigned integer
|
||||
if ft.Size() == 4 {
|
||||
return s.float32ToUint32(n, x, ft, tt)
|
||||
}
|
||||
if ft.Size() == 8 {
|
||||
return s.float64ToUint32(n, x, ft, tt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
s.Fatalf("weird float conversion %v -> %v", ft, tt)
|
||||
}
|
||||
op1, op2, it := conv.op1, conv.op2, conv.intermediateType
|
||||
|
||||
if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
|
||||
// normal case, not tripping over unsigned 64
|
||||
if op1 == ssa.OpCopy {
|
||||
if op2 == ssa.OpCopy {
|
||||
return x
|
||||
}
|
||||
return s.newValueOrSfCall1(op2, n.Type(), x)
|
||||
}
|
||||
if op2 == ssa.OpCopy {
|
||||
return s.newValueOrSfCall1(op1, n.Type(), x)
|
||||
}
|
||||
return s.newValueOrSfCall1(op2, n.Type(), s.newValueOrSfCall1(op1, types.Types[it], x))
|
||||
}
|
||||
// Tricky 64-bit unsigned cases.
|
||||
if ft.IsInteger() {
|
||||
// tt is float32 or float64, and ft is also unsigned
|
||||
if tt.Size() == 4 {
|
||||
return s.uint64Tofloat32(n, x, ft, tt)
|
||||
}
|
||||
if tt.Size() == 8 {
|
||||
return s.uint64Tofloat64(n, x, ft, tt)
|
||||
}
|
||||
s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
|
||||
}
|
||||
// ft is float32 or float64, and tt is unsigned integer
|
||||
if ft.Size() == 4 {
|
||||
return s.float32ToUint64(n, x, ft, tt)
|
||||
}
|
||||
if ft.Size() == 8 {
|
||||
return s.float64ToUint64(n, x, ft, tt)
|
||||
}
|
||||
s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
|
||||
return nil
|
||||
}
|
||||
|
||||
if ft.IsComplex() && tt.IsComplex() {
|
||||
var op ssa.Op
|
||||
if ft.Size() == tt.Size() {
|
||||
switch ft.Size() {
|
||||
case 8:
|
||||
op = ssa.OpRound32F
|
||||
case 16:
|
||||
op = ssa.OpRound64F
|
||||
default:
|
||||
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
|
||||
}
|
||||
} else if ft.Size() == 8 && tt.Size() == 16 {
|
||||
op = ssa.OpCvt32Fto64F
|
||||
} else if ft.Size() == 16 && tt.Size() == 8 {
|
||||
op = ssa.OpCvt64Fto32F
|
||||
} else {
|
||||
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
|
||||
}
|
||||
ftp := types.FloatForComplex(ft)
|
||||
ttp := types.FloatForComplex(tt)
|
||||
return s.newValue2(ssa.OpComplexMake, tt,
|
||||
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
|
||||
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
|
||||
}
|
||||
|
||||
s.Fatalf("unhandled OCONV %s -> %s", n.X.Type().Kind(), n.Type().Kind())
|
||||
return nil
|
||||
return s.conv(n, x, n.X.Type(), n.Type())
|
||||
|
||||
case ir.ODOTTYPE:
|
||||
n := n.(*ir.TypeAssertExpr)
|
||||
|
||||
@@ -73,7 +73,7 @@ func embedKind(typ *types.Type) int {
|
||||
if typ.Kind() == types.TSTRING {
|
||||
return embedString
|
||||
}
|
||||
if typ.Sym() == nil && typ.IsSlice() && typ.Elem().Kind() == types.TUINT8 {
|
||||
if typ.IsSlice() && typ.Elem().Kind() == types.TUINT8 {
|
||||
return embedBytes
|
||||
}
|
||||
return embedUnknown
|
||||
|
||||
@@ -1222,12 +1222,14 @@ func (r *importReader) node() ir.Node {
|
||||
switch op {
|
||||
case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER:
|
||||
n.Selection = r.exoticField()
|
||||
case ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
|
||||
case ir.OMETHEXPR:
|
||||
n = typecheckMethodExpr(n).(*ir.SelectorExpr)
|
||||
case ir.ODOTMETH, ir.OCALLPART:
|
||||
// These require a Lookup to link to the correct declaration.
|
||||
rcvrType := expr.Type()
|
||||
typ := n.Type()
|
||||
n.Selection = Lookdot(n, rcvrType, 1)
|
||||
if op == ir.OCALLPART || op == ir.OMETHEXPR {
|
||||
if op == ir.OCALLPART {
|
||||
// Lookdot clobbers the opcode and type, undo that.
|
||||
n.SetOp(op)
|
||||
n.SetType(typ)
|
||||
|
||||
@@ -383,10 +383,11 @@ func tcSelect(sel *ir.SelectStmt) {
|
||||
n := Stmt(ncase.Comm)
|
||||
ncase.Comm = n
|
||||
oselrecv2 := func(dst, recv ir.Node, def bool) {
|
||||
n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
n.Def = def
|
||||
n.SetTypecheck(1)
|
||||
ncase.Comm = n
|
||||
selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
selrecv.Def = def
|
||||
selrecv.SetTypecheck(1)
|
||||
selrecv.SetInit(n.Init())
|
||||
ncase.Comm = selrecv
|
||||
}
|
||||
switch n.Op() {
|
||||
default:
|
||||
|
||||
@@ -4,12 +4,15 @@ go 1.17
|
||||
|
||||
require (
|
||||
github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
|
||||
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
|
||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
|
||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
|
||||
golang.org/x/mod v0.5.1
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
||||
golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
|
||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
)
|
||||
|
||||
@@ -13,8 +13,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY=
|
||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
|
||||
@@ -2,17 +2,51 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Copied from Go distribution src/go/build/build.go, syslist.go
|
||||
// Copied from Go distribution src/go/build/build.go, syslist.go.
|
||||
// That package does not export the ability to process raw file data,
|
||||
// although we could fake it with an appropriate build.Context
|
||||
// and a lot of unwrapping.
|
||||
// More importantly, that package does not implement the tags["*"]
|
||||
// special case, in which both tag and !tag are considered to be true
|
||||
// for essentially all tags (except "ignore").
|
||||
//
|
||||
// If we added this API to go/build directly, we wouldn't need this
|
||||
// file anymore, but this API is not terribly general-purpose and we
|
||||
// don't really want to commit to any public form of it, nor do we
|
||||
// want to move the core parts of go/build into a top-level internal package.
|
||||
// These details change very infrequently, so the copy is fine.
|
||||
|
||||
package imports
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build/constraint"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var slashslash = []byte("//")
|
||||
var (
|
||||
bSlashSlash = []byte("//")
|
||||
bStarSlash = []byte("*/")
|
||||
bSlashStar = []byte("/*")
|
||||
bPlusBuild = []byte("+build")
|
||||
|
||||
goBuildComment = []byte("//go:build")
|
||||
|
||||
errGoBuildWithoutBuild = errors.New("//go:build comment without // +build comment")
|
||||
errMultipleGoBuild = errors.New("multiple //go:build comments")
|
||||
)
|
||||
|
||||
func isGoBuildComment(line []byte) bool {
|
||||
if !bytes.HasPrefix(line, goBuildComment) {
|
||||
return false
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
rest := line[len(goBuildComment):]
|
||||
return len(rest) == 0 || len(bytes.TrimSpace(rest)) < len(rest)
|
||||
}
|
||||
|
||||
// ShouldBuild reports whether it is okay to use this file,
|
||||
// The rule is that in the file's leading run of // comments
|
||||
@@ -34,90 +68,124 @@ var slashslash = []byte("//")
|
||||
// in any build.
|
||||
//
|
||||
func ShouldBuild(content []byte, tags map[string]bool) bool {
|
||||
// Pass 1. Identify leading run of // comments and blank lines,
|
||||
// Identify leading run of // comments and blank lines,
|
||||
// which must be followed by a blank line.
|
||||
end := 0
|
||||
p := content
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 { // Blank line
|
||||
end = len(content) - len(p)
|
||||
continue
|
||||
}
|
||||
if !bytes.HasPrefix(line, slashslash) { // Not comment line
|
||||
break
|
||||
}
|
||||
// Also identify any //go:build comments.
|
||||
content, goBuild, _, err := parseFileHeader(content)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
content = content[:end]
|
||||
|
||||
// Pass 2. Process each line in the run.
|
||||
p = content
|
||||
allok := true
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
// If //go:build line is present, it controls.
|
||||
// Otherwise fall back to +build processing.
|
||||
var shouldBuild bool
|
||||
switch {
|
||||
case goBuild != nil:
|
||||
x, err := constraint.Parse(string(goBuild))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if !bytes.HasPrefix(line, slashslash) {
|
||||
continue
|
||||
}
|
||||
line = bytes.TrimSpace(line[len(slashslash):])
|
||||
if len(line) > 0 && line[0] == '+' {
|
||||
// Looks like a comment +line.
|
||||
f := strings.Fields(string(line))
|
||||
if f[0] == "+build" {
|
||||
ok := false
|
||||
for _, tok := range f[1:] {
|
||||
if matchTags(tok, tags) {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
allok = false
|
||||
shouldBuild = eval(x, tags, true)
|
||||
|
||||
default:
|
||||
shouldBuild = true
|
||||
p := content
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if !bytes.HasPrefix(line, bSlashSlash) || !bytes.Contains(line, bPlusBuild) {
|
||||
continue
|
||||
}
|
||||
text := string(line)
|
||||
if !constraint.IsPlusBuild(text) {
|
||||
continue
|
||||
}
|
||||
if x, err := constraint.Parse(text); err == nil {
|
||||
if !eval(x, tags, true) {
|
||||
shouldBuild = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allok
|
||||
return shouldBuild
|
||||
}
|
||||
|
||||
// matchTags reports whether the name is one of:
|
||||
//
|
||||
// tag (if tags[tag] is true)
|
||||
// !tag (if tags[tag] is false)
|
||||
// a comma-separated list of any of these
|
||||
//
|
||||
func matchTags(name string, tags map[string]bool) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
|
||||
end := 0
|
||||
p := content
|
||||
ended := false // found non-blank, non-// line, so stopped accepting // +build lines
|
||||
inSlashStar := false // in /* */ comment
|
||||
|
||||
Lines:
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 && !ended { // Blank line
|
||||
// Remember position of most recent blank line.
|
||||
// When we find the first non-blank, non-// line,
|
||||
// this "end" position marks the latest file position
|
||||
// where a // +build line can appear.
|
||||
// (It must appear _before_ a blank line before the non-blank, non-// line.
|
||||
// Yes, that's confusing, which is part of why we moved to //go:build lines.)
|
||||
// Note that ended==false here means that inSlashStar==false,
|
||||
// since seeing a /* would have set ended==true.
|
||||
end = len(content) - len(p)
|
||||
continue Lines
|
||||
}
|
||||
if !bytes.HasPrefix(line, bSlashSlash) { // Not comment line
|
||||
ended = true
|
||||
}
|
||||
|
||||
if !inSlashStar && isGoBuildComment(line) {
|
||||
if goBuild != nil {
|
||||
return nil, nil, false, errMultipleGoBuild
|
||||
}
|
||||
goBuild = line
|
||||
}
|
||||
|
||||
Comments:
|
||||
for len(line) > 0 {
|
||||
if inSlashStar {
|
||||
if i := bytes.Index(line, bStarSlash); i >= 0 {
|
||||
inSlashStar = false
|
||||
line = bytes.TrimSpace(line[i+len(bStarSlash):])
|
||||
continue Comments
|
||||
}
|
||||
continue Lines
|
||||
}
|
||||
if bytes.HasPrefix(line, bSlashSlash) {
|
||||
continue Lines
|
||||
}
|
||||
if bytes.HasPrefix(line, bSlashStar) {
|
||||
inSlashStar = true
|
||||
line = bytes.TrimSpace(line[len(bSlashStar):])
|
||||
continue Comments
|
||||
}
|
||||
// Found non-comment text.
|
||||
break Lines
|
||||
}
|
||||
}
|
||||
if i := strings.Index(name, ","); i >= 0 {
|
||||
// comma-separated list
|
||||
ok1 := matchTags(name[:i], tags)
|
||||
ok2 := matchTags(name[i+1:], tags)
|
||||
return ok1 && ok2
|
||||
}
|
||||
if strings.HasPrefix(name, "!!") { // bad syntax, reject always
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(name, "!") { // negation
|
||||
return len(name) > 1 && matchTag(name[1:], tags, false)
|
||||
}
|
||||
return matchTag(name, tags, true)
|
||||
|
||||
return content[:end], goBuild, sawBinaryOnly, nil
|
||||
}
|
||||
|
||||
// matchTag reports whether the tag name is valid and satisfied by tags[name]==want.
|
||||
func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||
// matchTag reports whether the tag name is valid and tags[name] is true.
|
||||
// As a special case, if tags["*"] is true and name is not empty or ignore,
|
||||
// then matchTag will return prefer instead of the actual answer,
|
||||
// which allows the caller to pretend in that case that most tags are
|
||||
// both true and false.
|
||||
func matchTag(name string, tags map[string]bool, prefer bool) bool {
|
||||
// Tags must be letters, digits, underscores or dots.
|
||||
// Unlike in Go identifiers, all digits are fine (e.g., "386").
|
||||
for _, c := range name {
|
||||
@@ -131,7 +199,7 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||
// if we put * in the tags map then all tags
|
||||
// except "ignore" are considered both present and not
|
||||
// (so we return true no matter how 'want' is set).
|
||||
return true
|
||||
return prefer
|
||||
}
|
||||
|
||||
have := tags[name]
|
||||
@@ -144,7 +212,25 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||
if name == "darwin" {
|
||||
have = have || tags["ios"]
|
||||
}
|
||||
return have == want
|
||||
return have
|
||||
}
|
||||
|
||||
// eval is like
|
||||
// x.Eval(func(tag string) bool { return matchTag(tag, tags) })
|
||||
// except that it implements the special case for tags["*"] meaning
|
||||
// all tags are both true and false at the same time.
|
||||
func eval(x constraint.Expr, tags map[string]bool, prefer bool) bool {
|
||||
switch x := x.(type) {
|
||||
case *constraint.TagExpr:
|
||||
return matchTag(x.Tag, tags, prefer)
|
||||
case *constraint.NotExpr:
|
||||
return !eval(x.X, tags, !prefer)
|
||||
case *constraint.AndExpr:
|
||||
return eval(x.X, tags, prefer) && eval(x.Y, tags, prefer)
|
||||
case *constraint.OrExpr:
|
||||
return eval(x.X, tags, prefer) || eval(x.Y, tags, prefer)
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected constraint expression %T", x))
|
||||
}
|
||||
|
||||
// MatchFile returns false if the name contains a $GOOS or $GOARCH
|
||||
|
||||
@@ -190,8 +190,8 @@ func limiterForEdit(ctx context.Context, rs *Requirements, tryUpgrade, mustSelec
|
||||
|
||||
// raiseLimitsForUpgrades increases the module versions in maxVersions to the
|
||||
// versions that would be needed to allow each of the modules in tryUpgrade
|
||||
// (individually) and all of the modules in mustSelect (simultaneously) to be
|
||||
// added as roots.
|
||||
// (individually or in any combination) and all of the modules in mustSelect
|
||||
// (simultaneously) to be added as roots.
|
||||
//
|
||||
// Versions not present in maxVersion are unrestricted, and it is assumed that
|
||||
// they will not be promoted to root requirements (and thus will not contribute
|
||||
@@ -213,18 +213,42 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
||||
}
|
||||
}
|
||||
|
||||
var eagerUpgrades []module.Version
|
||||
var (
|
||||
eagerUpgrades []module.Version
|
||||
isLazyRootPath map[string]bool
|
||||
)
|
||||
if depth == eager {
|
||||
eagerUpgrades = tryUpgrade
|
||||
} else {
|
||||
isLazyRootPath = make(map[string]bool, len(maxVersion))
|
||||
for p := range maxVersion {
|
||||
isLazyRootPath[p] = true
|
||||
}
|
||||
for _, m := range tryUpgrade {
|
||||
isLazyRootPath[m.Path] = true
|
||||
}
|
||||
for _, m := range mustSelect {
|
||||
isLazyRootPath[m.Path] = true
|
||||
}
|
||||
|
||||
allowedRoot := map[module.Version]bool{}
|
||||
|
||||
var allowRoot func(m module.Version) error
|
||||
allowRoot = func(m module.Version) error {
|
||||
if allowedRoot[m] {
|
||||
return nil
|
||||
}
|
||||
allowedRoot[m] = true
|
||||
|
||||
if m.Path == Target.Path {
|
||||
// Target is already considered to be higher than any possible m, so we
|
||||
// won't be upgrading to it anyway and there is no point scanning its
|
||||
// dependencies.
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
|
||||
allow(m)
|
||||
|
||||
summary, err := goModSummary(m)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -234,12 +258,27 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
||||
// graph, rather than loading the (potentially-overlapping) subgraph for
|
||||
// each upgrade individually.
|
||||
eagerUpgrades = append(eagerUpgrades, m)
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, r := range summary.require {
|
||||
allow(r)
|
||||
if isLazyRootPath[r.Path] {
|
||||
// r could become a root as the result of an upgrade or downgrade,
|
||||
// in which case its dependencies will not be pruned out.
|
||||
// We need to allow those dependencies to be upgraded too.
|
||||
if err := allowRoot(r); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// r will not become a root, so its dependencies don't matter.
|
||||
// Allow only r itself.
|
||||
allow(r)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, m := range tryUpgrade {
|
||||
allowRoot(m)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,16 +307,41 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
||||
}
|
||||
}
|
||||
|
||||
if len(mustSelect) > 0 {
|
||||
mustGraph, err := readModGraph(ctx, depth, mustSelect)
|
||||
// Explicitly allow any (transitive) upgrades implied by mustSelect.
|
||||
nextRoots := append([]module.Version(nil), mustSelect...)
|
||||
for nextRoots != nil {
|
||||
module.Sort(nextRoots)
|
||||
rs := newRequirements(depth, nextRoots, nil)
|
||||
nextRoots = nil
|
||||
|
||||
rs, mustGraph, err := expandGraph(ctx, rs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, r := range mustGraph.BuildList() {
|
||||
// Some module in mustSelect requires r, so we must allow at least r.Version
|
||||
// unless it conflicts with an entry in mustSelect.
|
||||
// Some module in mustSelect requires r, so we must allow at least
|
||||
// r.Version (unless it conflicts with another entry in mustSelect, in
|
||||
// which case we will error out either way).
|
||||
allow(r)
|
||||
|
||||
if isLazyRootPath[r.Path] {
|
||||
if v, ok := rs.rootSelected(r.Path); ok && r.Version == v {
|
||||
// r is already a root, so its requirements are already included in
|
||||
// the build list.
|
||||
continue
|
||||
}
|
||||
|
||||
// The dependencies in mustSelect may upgrade (or downgrade) an existing
|
||||
// root to match r, which will remain as a root. However, since r is not
|
||||
// a root of rs, its dependencies have been pruned out of this build
|
||||
// list. We need to add it back explicitly so that we allow any
|
||||
// transitive upgrades that r will pull in.
|
||||
if nextRoots == nil {
|
||||
nextRoots = rs.rootModules // already capped
|
||||
}
|
||||
nextRoots = append(nextRoots, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ var extraEnvKeys = []string{
|
||||
"GO_TESTING_GOTOOLS", // for gccgo testing
|
||||
"GCCGO", // for gccgo testing
|
||||
"GCCGOTOOLDIR", // for gccgo testing
|
||||
"MallocNanoZone", // Needed to work around an apparent kernel bug in macOS 12; see https://golang.org/issue/49138.
|
||||
}
|
||||
|
||||
// setup sets up the test execution temporary directory and environment.
|
||||
|
||||
41
src/cmd/go/testdata/script/list_all_gobuild.txt
vendored
Normal file
41
src/cmd/go/testdata/script/list_all_gobuild.txt
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# go list all should work with GOOS=linux because all packages build on Linux
|
||||
env GOOS=linux
|
||||
go list all
|
||||
|
||||
# go list all should work with GOOS=darwin, but it used to fail because
|
||||
# in the absence of //go:build support, p looked like it needed q
|
||||
# (p_test.go was not properly excluded), and q was Linux-only.
|
||||
#
|
||||
# Also testing with r and s that +build lines keep working.
|
||||
env GOOS=darwin
|
||||
go list all
|
||||
|
||||
-- go.mod --
|
||||
go 1.17
|
||||
module m
|
||||
|
||||
-- p/p.go --
|
||||
package p
|
||||
|
||||
-- p/p_test.go --
|
||||
//go:build linux
|
||||
|
||||
package p
|
||||
|
||||
import "m/q"
|
||||
|
||||
-- q/q_linux.go --
|
||||
package q
|
||||
|
||||
-- r/r.go --
|
||||
package r
|
||||
|
||||
-- r/r_test.go --
|
||||
// +build linux
|
||||
|
||||
package r
|
||||
|
||||
import "m/s"
|
||||
|
||||
-- s/s_linux.go --
|
||||
package s
|
||||
67
src/cmd/go/testdata/script/mod_all.txt
vendored
67
src/cmd/go/testdata/script/mod_all.txt
vendored
@@ -202,9 +202,9 @@ go mod edit -go=1.17 u/go.mod
|
||||
go mod edit -go=1.17 w/go.mod
|
||||
go mod edit -go=1.17 x/go.mod
|
||||
go mod edit -go=1.17
|
||||
cp go.mod go.mod.orig
|
||||
cmp go.mod go.mod.beforetidy
|
||||
go mod tidy
|
||||
cmp go.mod go.mod.orig
|
||||
cmp go.mod go.mod.aftertidy
|
||||
|
||||
# With lazy loading, 'go list all' with neither -mod=vendor nor -test should
|
||||
# match -mod=vendor without -test in 1.15.
|
||||
@@ -466,3 +466,66 @@ module example.com/x
|
||||
go 1.15
|
||||
-- x/x.go --
|
||||
package x
|
||||
-- go.mod.beforetidy --
|
||||
module example.com/main
|
||||
|
||||
// Note: this go.mod file initially specifies go 1.15,
|
||||
// but includes some redundant roots so that it
|
||||
// also already obeys the 1.17 lazy loading invariants.
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
example.com/a v0.1.0
|
||||
example.com/b v0.1.0 // indirect
|
||||
example.com/q v0.1.0
|
||||
example.com/r v0.1.0 // indirect
|
||||
example.com/t v0.1.0
|
||||
example.com/u v0.1.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
example.com/a v0.1.0 => ./a
|
||||
example.com/b v0.1.0 => ./b
|
||||
example.com/c v0.1.0 => ./c
|
||||
example.com/d v0.1.0 => ./d
|
||||
example.com/q v0.1.0 => ./q
|
||||
example.com/r v0.1.0 => ./r
|
||||
example.com/s v0.1.0 => ./s
|
||||
example.com/t v0.1.0 => ./t
|
||||
example.com/u v0.1.0 => ./u
|
||||
example.com/w v0.1.0 => ./w
|
||||
example.com/x v0.1.0 => ./x
|
||||
)
|
||||
-- go.mod.aftertidy --
|
||||
module example.com/main
|
||||
|
||||
// Note: this go.mod file initially specifies go 1.15,
|
||||
// but includes some redundant roots so that it
|
||||
// also already obeys the 1.17 lazy loading invariants.
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
example.com/a v0.1.0
|
||||
example.com/q v0.1.0
|
||||
example.com/t v0.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
example.com/b v0.1.0 // indirect
|
||||
example.com/r v0.1.0 // indirect
|
||||
example.com/u v0.1.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
example.com/a v0.1.0 => ./a
|
||||
example.com/b v0.1.0 => ./b
|
||||
example.com/c v0.1.0 => ./c
|
||||
example.com/d v0.1.0 => ./d
|
||||
example.com/q v0.1.0 => ./q
|
||||
example.com/r v0.1.0 => ./r
|
||||
example.com/s v0.1.0 => ./s
|
||||
example.com/t v0.1.0 => ./t
|
||||
example.com/u v0.1.0 => ./u
|
||||
example.com/w v0.1.0 => ./w
|
||||
example.com/x v0.1.0 => ./x
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ env GO111MODULE=on
|
||||
env GOPROXY=direct
|
||||
env GOSUMDB=off
|
||||
|
||||
go list -m cloud.google.com/go@master
|
||||
go list -m cloud.google.com/go@main
|
||||
! stdout 'v0.0.0-'
|
||||
|
||||
-- go.mod --
|
||||
|
||||
117
src/cmd/go/testdata/script/mod_get_issue47979.txt
vendored
Normal file
117
src/cmd/go/testdata/script/mod_get_issue47979.txt
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
# Regression test for https://golang.org/issue/47979:
|
||||
#
|
||||
# An argument to 'go get' that results in an upgrade to a different existing
|
||||
# root should be allowed, and should not panic the 'go' command.
|
||||
|
||||
cp go.mod go.mod.orig
|
||||
|
||||
|
||||
# Transitive upgrades from upgraded roots should not prevent
|
||||
# 'go get -u' from performing upgrades.
|
||||
|
||||
cp go.mod.orig go.mod
|
||||
go get -u -d .
|
||||
cmp go.mod go.mod.want
|
||||
|
||||
|
||||
# 'go get' of a specific version should allow upgrades of
|
||||
# every dependency (transitively) required by that version,
|
||||
# including dependencies that are pulled into the module
|
||||
# graph by upgrading other root requirements
|
||||
# (in this case, example.net/indirect).
|
||||
|
||||
cp go.mod.orig go.mod
|
||||
go get -d example.net/a@v0.2.0
|
||||
cmp go.mod go.mod.want
|
||||
|
||||
|
||||
-- go.mod --
|
||||
module golang.org/issue47979
|
||||
|
||||
go 1.17
|
||||
|
||||
replace (
|
||||
example.net/a v0.1.0 => ./a1
|
||||
example.net/a v0.2.0 => ./a2
|
||||
example.net/indirect v0.1.0 => ./indirect1
|
||||
example.net/indirect v0.2.0 => ./indirect2
|
||||
example.net/other v0.1.0 => ./other
|
||||
example.net/other v0.2.0 => ./other
|
||||
)
|
||||
|
||||
require (
|
||||
example.net/a v0.1.0
|
||||
example.net/other v0.1.0
|
||||
)
|
||||
|
||||
require example.net/indirect v0.1.0 // indirect
|
||||
-- go.mod.want --
|
||||
module golang.org/issue47979
|
||||
|
||||
go 1.17
|
||||
|
||||
replace (
|
||||
example.net/a v0.1.0 => ./a1
|
||||
example.net/a v0.2.0 => ./a2
|
||||
example.net/indirect v0.1.0 => ./indirect1
|
||||
example.net/indirect v0.2.0 => ./indirect2
|
||||
example.net/other v0.1.0 => ./other
|
||||
example.net/other v0.2.0 => ./other
|
||||
)
|
||||
|
||||
require (
|
||||
example.net/a v0.2.0
|
||||
example.net/other v0.2.0
|
||||
)
|
||||
|
||||
require example.net/indirect v0.2.0 // indirect
|
||||
-- issue.go --
|
||||
package issue
|
||||
|
||||
import _ "example.net/a"
|
||||
-- useother/useother.go --
|
||||
package useother
|
||||
|
||||
import _ "example.net/other"
|
||||
-- a1/go.mod --
|
||||
module example.net/a
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.net/indirect v0.1.0
|
||||
-- a1/a.go --
|
||||
package a
|
||||
-- a2/go.mod --
|
||||
module example.net/a
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.net/indirect v0.2.0
|
||||
-- a2/a.go --
|
||||
package a
|
||||
|
||||
import "example.net/indirect"
|
||||
-- indirect1/go.mod --
|
||||
module example.net/indirect
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.net/other v0.1.0
|
||||
-- indirect1/indirect.go --
|
||||
package indirect
|
||||
-- indirect2/go.mod --
|
||||
module example.net/indirect
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.net/other v0.2.0
|
||||
-- indirect2/indirect.go --
|
||||
package indirect
|
||||
|
||||
import "example.net/other"
|
||||
-- other/go.mod --
|
||||
module example.net/other
|
||||
|
||||
go 1.17
|
||||
-- other/other.go --
|
||||
package other
|
||||
68
src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt
vendored
Normal file
68
src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# Check that 'go get -u' will upgrade a dependency (direct or indirect)
|
||||
# when the main module and the dependency are both lazy.
|
||||
# Verifies #47768.
|
||||
|
||||
# Check that go.mod is tidy, and an upgrade is available.
|
||||
cp go.mod go.mod.orig
|
||||
go mod tidy
|
||||
cmp go.mod go.mod.orig
|
||||
|
||||
go list -m -u example.com/lazyupgrade
|
||||
stdout '^example.com/lazyupgrade v0.1.0 \[v0.1.1\] => ./lazyupgrade@v0.1.0$'
|
||||
|
||||
# 'go get -u' on a package that directly imports the dependency should upgrade.
|
||||
go get -u ./usedirect
|
||||
go list -m example.com/lazyupgrade
|
||||
stdout '^example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1$'
|
||||
cp go.mod.orig go.mod
|
||||
|
||||
# 'go get -u' on a package that indirectly imports the dependency should upgrade.
|
||||
go get -u ./useindirect
|
||||
go list -m example.com/lazyupgrade
|
||||
stdout '^example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1$'
|
||||
|
||||
-- go.mod --
|
||||
module use
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
direct v0.0.0
|
||||
example.com/lazyupgrade v0.1.0
|
||||
)
|
||||
|
||||
replace (
|
||||
direct => ./direct
|
||||
example.com/lazyupgrade v0.1.0 => ./lazyupgrade@v0.1.0
|
||||
example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1
|
||||
)
|
||||
-- usedirect/usedirect.go --
|
||||
package use
|
||||
|
||||
import _ "example.com/lazyupgrade"
|
||||
-- useindirect/useindirect.go --
|
||||
package use
|
||||
|
||||
import _ "direct"
|
||||
-- direct/go.mod --
|
||||
module direct
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.com/lazyupgrade v0.1.0
|
||||
-- direct/direct.go --
|
||||
package direct
|
||||
|
||||
import _ "example.com/lazyupgrade"
|
||||
-- lazyupgrade@v0.1.0/go.mod --
|
||||
module example.com/lazyupgrade
|
||||
|
||||
go 1.17
|
||||
-- lazyupgrade@v0.1.0/lazyupgrade.go --
|
||||
package lazyupgrade
|
||||
-- lazyupgrade@v0.1.1/go.mod --
|
||||
module example.com/lazyupgrade
|
||||
|
||||
go 1.17
|
||||
-- lazyupgrade@v0.1.1/lazyupgrade.go --
|
||||
package lazyupgrade
|
||||
22
src/cmd/go/testdata/script/mod_retention.txt
vendored
22
src/cmd/go/testdata/script/mod_retention.txt
vendored
@@ -81,14 +81,14 @@ require (
|
||||
package x
|
||||
import _ "rsc.io/quote"
|
||||
-- go.mod.crlf --
|
||||
module m
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2
|
||||
rsc.io/testonly v1.0.0 // indirect
|
||||
)
|
||||
module m
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2
|
||||
rsc.io/testonly v1.0.0 // indirect
|
||||
)
|
||||
-- go.mod.unsorted --
|
||||
module m
|
||||
|
||||
@@ -139,10 +139,10 @@ module m
|
||||
|
||||
go $goversion
|
||||
|
||||
require rsc.io/quote v1.5.2
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
|
||||
rsc.io/sampler v1.3.0 // indirect
|
||||
rsc.io/testonly v1.0.0 // indirect
|
||||
)
|
||||
|
||||
require golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
|
||||
|
||||
@@ -72,10 +72,9 @@ go 1.17
|
||||
|
||||
replace example.net/indirect v0.1.0 => ./indirect
|
||||
|
||||
require (
|
||||
example.net/ambiguous/nested v0.1.0 // indirect
|
||||
example.net/indirect v0.1.0
|
||||
)
|
||||
require example.net/indirect v0.1.0
|
||||
|
||||
require example.net/ambiguous/nested v0.1.0 // indirect
|
||||
-- all-m.txt --
|
||||
example.com/m
|
||||
example.net/ambiguous v0.1.0
|
||||
|
||||
@@ -97,10 +97,9 @@ replace (
|
||||
example.net/requireincompatible v0.1.0 => ./requireincompatible
|
||||
)
|
||||
|
||||
require (
|
||||
example.com/retract/incompatible v1.0.0 // indirect
|
||||
example.net/lazy v0.1.0
|
||||
)
|
||||
require example.net/lazy v0.1.0
|
||||
|
||||
require example.com/retract/incompatible v1.0.0 // indirect
|
||||
-- incompatible.go --
|
||||
package incompatible
|
||||
|
||||
|
||||
@@ -602,7 +602,7 @@ func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
|
||||
rs := r.Xsym
|
||||
rt := r.Type
|
||||
|
||||
if r.Xadd != signext21(r.Xadd) {
|
||||
if rt == objabi.R_ADDRARM64 && r.Xadd != signext21(r.Xadd) {
|
||||
// If the relocation target would overflow the addend, then target
|
||||
// a linker-manufactured label symbol with a smaller addend instead.
|
||||
label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd/peRelocLimit*peRelocLimit), ldr.SymVersion(rs))
|
||||
|
||||
@@ -2450,6 +2450,12 @@ func splitTextSections(ctxt *Link) bool {
|
||||
return (ctxt.IsPPC64() || (ctxt.IsARM64() && ctxt.IsDarwin())) && ctxt.IsExternal()
|
||||
}
|
||||
|
||||
// On Wasm, we reserve 4096 bytes for zero page, then 8192 bytes for wasm_exec.js
|
||||
// to store command line args and environment variables.
|
||||
// Data sections starts from at least address 12288.
|
||||
// Keep in sync with wasm_exec.js.
|
||||
const wasmMinDataAddr = 4096 + 8192
|
||||
|
||||
// address assigns virtual addresses to all segments and sections and
|
||||
// returns all segments in file order.
|
||||
func (ctxt *Link) address() []*sym.Segment {
|
||||
@@ -2459,10 +2465,14 @@ func (ctxt *Link) address() []*sym.Segment {
|
||||
order = append(order, &Segtext)
|
||||
Segtext.Rwx = 05
|
||||
Segtext.Vaddr = va
|
||||
for _, s := range Segtext.Sections {
|
||||
for i, s := range Segtext.Sections {
|
||||
va = uint64(Rnd(int64(va), int64(s.Align)))
|
||||
s.Vaddr = va
|
||||
va += s.Length
|
||||
|
||||
if ctxt.IsWasm() && i == 0 && va < wasmMinDataAddr {
|
||||
va = wasmMinDataAddr
|
||||
}
|
||||
}
|
||||
|
||||
Segtext.Length = va - uint64(*FlagTextAddr)
|
||||
|
||||
@@ -132,7 +132,9 @@ func (d *deadcodePass) flood() {
|
||||
methods = methods[:0]
|
||||
for i := 0; i < relocs.Count(); i++ {
|
||||
r := relocs.At(i)
|
||||
if r.Weak() {
|
||||
// When build with "-linkshared", we can't tell if the interface
|
||||
// method in itab will be used or not. Ignore the weak attribute.
|
||||
if r.Weak() && !(d.ctxt.linkShared && d.ldr.IsItab(symIdx)) {
|
||||
continue
|
||||
}
|
||||
t := r.Type()
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"fmt"
|
||||
"internal/buildcfg"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -1749,7 +1750,7 @@ func asmbElf(ctxt *Link) {
|
||||
sh.Flags = uint64(elf.SHF_ALLOC)
|
||||
sh.Addralign = 1
|
||||
|
||||
if interpreter == "" && buildcfg.GO_LDSO != "" {
|
||||
if interpreter == "" && buildcfg.GOOS == runtime.GOOS && buildcfg.GOARCH == runtime.GOARCH && buildcfg.GO_LDSO != "" {
|
||||
interpreter = buildcfg.GO_LDSO
|
||||
}
|
||||
|
||||
|
||||
@@ -993,13 +993,31 @@ package main
|
||||
|
||||
var x = [1<<25]byte{1<<23: 23, 1<<24: 24}
|
||||
|
||||
var addr = [...]*byte{
|
||||
&x[1<<23-1],
|
||||
&x[1<<23],
|
||||
&x[1<<23+1],
|
||||
&x[1<<24-1],
|
||||
&x[1<<24],
|
||||
&x[1<<24+1],
|
||||
}
|
||||
|
||||
func main() {
|
||||
// check relocations in instructions
|
||||
check(x[1<<23-1], 0)
|
||||
check(x[1<<23], 23)
|
||||
check(x[1<<23+1], 0)
|
||||
check(x[1<<24-1], 0)
|
||||
check(x[1<<24], 24)
|
||||
check(x[1<<24+1], 0)
|
||||
|
||||
// check absolute address relocations in data
|
||||
check(*addr[0], 0)
|
||||
check(*addr[1], 23)
|
||||
check(*addr[2], 0)
|
||||
check(*addr[3], 0)
|
||||
check(*addr[4], 24)
|
||||
check(*addr[5], 0)
|
||||
}
|
||||
|
||||
func check(x, y byte) {
|
||||
|
||||
313
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
313
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
@@ -956,170 +956,217 @@ func (f *File) SetRequire(req []*Require) {
|
||||
|
||||
// SetRequireSeparateIndirect updates the requirements of f to contain the given
|
||||
// requirements. Comment contents (except for 'indirect' markings) are retained
|
||||
// from the first existing requirement for each module path, and block structure
|
||||
// is maintained as long as the indirect markings match.
|
||||
// from the first existing requirement for each module path. Like SetRequire,
|
||||
// SetRequireSeparateIndirect adds requirements for new paths in req,
|
||||
// updates the version and "// indirect" comment on existing requirements,
|
||||
// and deletes requirements on paths not in req. Existing duplicate requirements
|
||||
// are deleted.
|
||||
//
|
||||
// Any requirements on paths not already present in the file are added. Direct
|
||||
// requirements are added to the last block containing *any* other direct
|
||||
// requirement. Indirect requirements are added to the last block containing
|
||||
// *only* other indirect requirements. If no suitable block exists, a new one is
|
||||
// added, with the last block containing a direct dependency (if any)
|
||||
// immediately before the first block containing only indirect dependencies.
|
||||
// As its name suggests, SetRequireSeparateIndirect puts direct and indirect
|
||||
// requirements into two separate blocks, one containing only direct
|
||||
// requirements, and the other containing only indirect requirements.
|
||||
// SetRequireSeparateIndirect may move requirements between these two blocks
|
||||
// when their indirect markings change. However, SetRequireSeparateIndirect
|
||||
// won't move requirements from other blocks, especially blocks with comments.
|
||||
//
|
||||
// The Syntax field is ignored for requirements in the given blocks.
|
||||
// If the file initially has one uncommented block of requirements,
|
||||
// SetRequireSeparateIndirect will split it into a direct-only and indirect-only
|
||||
// block. This aids in the transition to separate blocks.
|
||||
func (f *File) SetRequireSeparateIndirect(req []*Require) {
|
||||
type modKey struct {
|
||||
path string
|
||||
indirect bool
|
||||
}
|
||||
need := make(map[modKey]string)
|
||||
for _, r := range req {
|
||||
need[modKey{r.Mod.Path, r.Indirect}] = r.Mod.Version
|
||||
// hasComments returns whether a line or block has comments
|
||||
// other than "indirect".
|
||||
hasComments := func(c Comments) bool {
|
||||
return len(c.Before) > 0 || len(c.After) > 0 || len(c.Suffix) > 1 ||
|
||||
(len(c.Suffix) == 1 &&
|
||||
strings.TrimSpace(strings.TrimPrefix(c.Suffix[0].Token, string(slashSlash))) != "indirect")
|
||||
}
|
||||
|
||||
comments := make(map[string]Comments)
|
||||
for _, r := range f.Require {
|
||||
v, ok := need[modKey{r.Mod.Path, r.Indirect}]
|
||||
if !ok {
|
||||
if _, ok := need[modKey{r.Mod.Path, !r.Indirect}]; ok {
|
||||
if _, dup := comments[r.Mod.Path]; !dup {
|
||||
comments[r.Mod.Path] = r.Syntax.Comments
|
||||
}
|
||||
// moveReq adds r to block. If r was in another block, moveReq deletes
|
||||
// it from that block and transfers its comments.
|
||||
moveReq := func(r *Require, block *LineBlock) {
|
||||
var line *Line
|
||||
if r.Syntax == nil {
|
||||
line = &Line{Token: []string{AutoQuote(r.Mod.Path), r.Mod.Version}}
|
||||
r.Syntax = line
|
||||
if r.Indirect {
|
||||
r.setIndirect(true)
|
||||
}
|
||||
r.markRemoved()
|
||||
continue
|
||||
} else {
|
||||
line = new(Line)
|
||||
*line = *r.Syntax
|
||||
if !line.InBlock && len(line.Token) > 0 && line.Token[0] == "require" {
|
||||
line.Token = line.Token[1:]
|
||||
}
|
||||
r.Syntax.Token = nil // Cleanup will delete the old line.
|
||||
r.Syntax = line
|
||||
}
|
||||
r.setVersion(v)
|
||||
delete(need, modKey{r.Mod.Path, r.Indirect})
|
||||
line.InBlock = true
|
||||
block.Line = append(block.Line, line)
|
||||
}
|
||||
|
||||
// Examine existing require lines and blocks.
|
||||
var (
|
||||
lastDirectOrMixedBlock Expr
|
||||
firstIndirectOnlyBlock Expr
|
||||
lastIndirectOnlyBlock Expr
|
||||
// We may insert new requirements into the last uncommented
|
||||
// direct-only and indirect-only blocks. We may also move requirements
|
||||
// to the opposite block if their indirect markings change.
|
||||
lastDirectIndex = -1
|
||||
lastIndirectIndex = -1
|
||||
|
||||
// If there are no direct-only or indirect-only blocks, a new block may
|
||||
// be inserted after the last require line or block.
|
||||
lastRequireIndex = -1
|
||||
|
||||
// If there's only one require line or block, and it's uncommented,
|
||||
// we'll move its requirements to the direct-only or indirect-only blocks.
|
||||
requireLineOrBlockCount = 0
|
||||
|
||||
// Track the block each requirement belongs to (if any) so we can
|
||||
// move them later.
|
||||
lineToBlock = make(map[*Line]*LineBlock)
|
||||
)
|
||||
for _, stmt := range f.Syntax.Stmt {
|
||||
for i, stmt := range f.Syntax.Stmt {
|
||||
switch stmt := stmt.(type) {
|
||||
case *Line:
|
||||
if len(stmt.Token) == 0 || stmt.Token[0] != "require" {
|
||||
continue
|
||||
}
|
||||
if isIndirect(stmt) {
|
||||
lastIndirectOnlyBlock = stmt
|
||||
} else {
|
||||
lastDirectOrMixedBlock = stmt
|
||||
lastRequireIndex = i
|
||||
requireLineOrBlockCount++
|
||||
if !hasComments(stmt.Comments) {
|
||||
if isIndirect(stmt) {
|
||||
lastIndirectIndex = i
|
||||
} else {
|
||||
lastDirectIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
case *LineBlock:
|
||||
if len(stmt.Token) == 0 || stmt.Token[0] != "require" {
|
||||
continue
|
||||
}
|
||||
indirectOnly := true
|
||||
lastRequireIndex = i
|
||||
requireLineOrBlockCount++
|
||||
allDirect := len(stmt.Line) > 0 && !hasComments(stmt.Comments)
|
||||
allIndirect := len(stmt.Line) > 0 && !hasComments(stmt.Comments)
|
||||
for _, line := range stmt.Line {
|
||||
if len(line.Token) == 0 {
|
||||
continue
|
||||
}
|
||||
if !isIndirect(line) {
|
||||
indirectOnly = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if indirectOnly {
|
||||
lastIndirectOnlyBlock = stmt
|
||||
if firstIndirectOnlyBlock == nil {
|
||||
firstIndirectOnlyBlock = stmt
|
||||
}
|
||||
} else {
|
||||
lastDirectOrMixedBlock = stmt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isOrContainsStmt := func(stmt Expr, target Expr) bool {
|
||||
if stmt == target {
|
||||
return true
|
||||
}
|
||||
if stmt, ok := stmt.(*LineBlock); ok {
|
||||
if target, ok := target.(*Line); ok {
|
||||
for _, line := range stmt.Line {
|
||||
if line == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
addRequire := func(path, vers string, indirect bool, comments Comments) {
|
||||
var line *Line
|
||||
if indirect {
|
||||
if lastIndirectOnlyBlock != nil {
|
||||
line = f.Syntax.addLine(lastIndirectOnlyBlock, "require", path, vers)
|
||||
} else {
|
||||
// Add a new require block after the last direct-only or mixed "require"
|
||||
// block (if any).
|
||||
//
|
||||
// (f.Syntax.addLine would add the line to an existing "require" block if
|
||||
// present, but here the existing "require" blocks are all direct-only, so
|
||||
// we know we need to add a new block instead.)
|
||||
line = &Line{Token: []string{"require", path, vers}}
|
||||
lastIndirectOnlyBlock = line
|
||||
firstIndirectOnlyBlock = line // only block implies first block
|
||||
if lastDirectOrMixedBlock == nil {
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, line)
|
||||
lineToBlock[line] = stmt
|
||||
if hasComments(line.Comments) {
|
||||
allDirect = false
|
||||
allIndirect = false
|
||||
} else if isIndirect(line) {
|
||||
allDirect = false
|
||||
} else {
|
||||
for i, stmt := range f.Syntax.Stmt {
|
||||
if isOrContainsStmt(stmt, lastDirectOrMixedBlock) {
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size
|
||||
copy(f.Syntax.Stmt[i+2:], f.Syntax.Stmt[i+1:]) // shuffle elements up
|
||||
f.Syntax.Stmt[i+1] = line
|
||||
break
|
||||
}
|
||||
}
|
||||
allIndirect = false
|
||||
}
|
||||
}
|
||||
if allDirect {
|
||||
lastDirectIndex = i
|
||||
}
|
||||
if allIndirect {
|
||||
lastIndirectIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oneFlatUncommentedBlock := requireLineOrBlockCount == 1 &&
|
||||
!hasComments(*f.Syntax.Stmt[lastRequireIndex].Comment())
|
||||
|
||||
// Create direct and indirect blocks if needed. Convert lines into blocks
|
||||
// if needed. If we end up with an empty block or a one-line block,
|
||||
// Cleanup will delete it or convert it to a line later.
|
||||
insertBlock := func(i int) *LineBlock {
|
||||
block := &LineBlock{Token: []string{"require"}}
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, nil)
|
||||
copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:])
|
||||
f.Syntax.Stmt[i] = block
|
||||
return block
|
||||
}
|
||||
|
||||
ensureBlock := func(i int) *LineBlock {
|
||||
switch stmt := f.Syntax.Stmt[i].(type) {
|
||||
case *LineBlock:
|
||||
return stmt
|
||||
case *Line:
|
||||
block := &LineBlock{
|
||||
Token: []string{"require"},
|
||||
Line: []*Line{stmt},
|
||||
}
|
||||
stmt.Token = stmt.Token[1:] // remove "require"
|
||||
stmt.InBlock = true
|
||||
f.Syntax.Stmt[i] = block
|
||||
return block
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected statement: %v", stmt))
|
||||
}
|
||||
}
|
||||
|
||||
var lastDirectBlock *LineBlock
|
||||
if lastDirectIndex < 0 {
|
||||
if lastIndirectIndex >= 0 {
|
||||
lastDirectIndex = lastIndirectIndex
|
||||
lastIndirectIndex++
|
||||
} else if lastRequireIndex >= 0 {
|
||||
lastDirectIndex = lastRequireIndex + 1
|
||||
} else {
|
||||
if lastDirectOrMixedBlock != nil {
|
||||
line = f.Syntax.addLine(lastDirectOrMixedBlock, "require", path, vers)
|
||||
lastDirectIndex = len(f.Syntax.Stmt)
|
||||
}
|
||||
lastDirectBlock = insertBlock(lastDirectIndex)
|
||||
} else {
|
||||
lastDirectBlock = ensureBlock(lastDirectIndex)
|
||||
}
|
||||
|
||||
var lastIndirectBlock *LineBlock
|
||||
if lastIndirectIndex < 0 {
|
||||
lastIndirectIndex = lastDirectIndex + 1
|
||||
lastIndirectBlock = insertBlock(lastIndirectIndex)
|
||||
} else {
|
||||
lastIndirectBlock = ensureBlock(lastIndirectIndex)
|
||||
}
|
||||
|
||||
// Delete requirements we don't want anymore.
|
||||
// Update versions and indirect comments on requirements we want to keep.
|
||||
// If a requirement is in last{Direct,Indirect}Block with the wrong
|
||||
// indirect marking after this, or if the requirement is in an single
|
||||
// uncommented mixed block (oneFlatUncommentedBlock), move it to the
|
||||
// correct block.
|
||||
//
|
||||
// Some blocks may be empty after this. Cleanup will remove them.
|
||||
need := make(map[string]*Require)
|
||||
for _, r := range req {
|
||||
need[r.Mod.Path] = r
|
||||
}
|
||||
have := make(map[string]*Require)
|
||||
for _, r := range f.Require {
|
||||
path := r.Mod.Path
|
||||
if need[path] == nil || have[path] != nil {
|
||||
// Requirement not needed, or duplicate requirement. Delete.
|
||||
r.markRemoved()
|
||||
continue
|
||||
}
|
||||
have[r.Mod.Path] = r
|
||||
r.setVersion(need[path].Mod.Version)
|
||||
r.setIndirect(need[path].Indirect)
|
||||
if need[path].Indirect &&
|
||||
(oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastDirectBlock) {
|
||||
moveReq(r, lastIndirectBlock)
|
||||
} else if !need[path].Indirect &&
|
||||
(oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastIndirectBlock) {
|
||||
moveReq(r, lastDirectBlock)
|
||||
}
|
||||
}
|
||||
|
||||
// Add new requirements.
|
||||
for path, r := range need {
|
||||
if have[path] == nil {
|
||||
if r.Indirect {
|
||||
moveReq(r, lastIndirectBlock)
|
||||
} else {
|
||||
// Add a new require block before the first indirect block (if any).
|
||||
//
|
||||
// That way if the file initially contains only indirect lines,
|
||||
// the direct lines still appear before it: we preserve existing
|
||||
// structure, but only to the extent that that structure already
|
||||
// reflects the direct/indirect split.
|
||||
line = &Line{Token: []string{"require", path, vers}}
|
||||
lastDirectOrMixedBlock = line
|
||||
if firstIndirectOnlyBlock == nil {
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, line)
|
||||
} else {
|
||||
for i, stmt := range f.Syntax.Stmt {
|
||||
if isOrContainsStmt(stmt, firstIndirectOnlyBlock) {
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size
|
||||
copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) // shuffle elements up
|
||||
f.Syntax.Stmt[i] = line
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
moveReq(r, lastDirectBlock)
|
||||
}
|
||||
f.Require = append(f.Require, r)
|
||||
}
|
||||
|
||||
line.Comments.Before = commentsAdd(line.Comments.Before, comments.Before)
|
||||
line.Comments.Suffix = commentsAdd(line.Comments.Suffix, comments.Suffix)
|
||||
|
||||
r := &Require{
|
||||
Mod: module.Version{Path: path, Version: vers},
|
||||
Indirect: indirect,
|
||||
Syntax: line,
|
||||
}
|
||||
r.setIndirect(indirect)
|
||||
f.Require = append(f.Require, r)
|
||||
}
|
||||
|
||||
for k, vers := range need {
|
||||
addRequire(k.path, vers, k.indirect, comments[k.path])
|
||||
}
|
||||
f.SortBlocks()
|
||||
}
|
||||
|
||||
|
||||
2
src/cmd/vendor/modules.txt
vendored
2
src/cmd/vendor/modules.txt
vendored
@@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
|
||||
## explicit; go 1.17
|
||||
golang.org/x/crypto/ed25519
|
||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||
# golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
|
||||
# golang.org/x/mod v0.5.1
|
||||
## explicit; go 1.17
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/modfile
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin || openbsd
|
||||
// +build darwin openbsd
|
||||
//go:build (darwin && !ios) || openbsd
|
||||
// +build darwin,!ios openbsd
|
||||
|
||||
package rand
|
||||
|
||||
|
||||
@@ -345,6 +345,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
if err := binary.Read(b, bo, &hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hdr.Iundefsym > uint32(len(f.Symtab.Syms)) {
|
||||
return nil, &FormatError{offset, fmt.Sprintf(
|
||||
"undefined symbols index in dynamic symbol table command is greater than symbol table length (%d > %d)",
|
||||
hdr.Iundefsym, len(f.Symtab.Syms)), nil}
|
||||
} else if hdr.Iundefsym+hdr.Nundefsym > uint32(len(f.Symtab.Syms)) {
|
||||
return nil, &FormatError{offset, fmt.Sprintf(
|
||||
"number of undefined symbols after index in dynamic symbol table command is greater than symbol table length (%d > %d)",
|
||||
hdr.Iundefsym+hdr.Nundefsym, len(f.Symtab.Syms)), nil}
|
||||
}
|
||||
dat := make([]byte, hdr.Nindirectsyms*4)
|
||||
if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -416,3 +416,10 @@ func TestTypeString(t *testing.T) {
|
||||
t.Errorf("got %v, want %v", TypeExec.GoString(), "macho.Exec")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenBadDysymCmd(t *testing.T) {
|
||||
_, err := openObscured("testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64")
|
||||
if err == nil {
|
||||
t.Fatal("openObscured did not fail when opening a file with an invalid dynamic symbol table command")
|
||||
}
|
||||
}
|
||||
|
||||
1
src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64
vendored
Normal file
1
src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -129,3 +129,43 @@ func TestUninitialized(t *testing.T) {
|
||||
t.Errorf("in uninitialized embed.FS, . is not a directory")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloT []T
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloUint8 []uint8
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloEUint8 []EmbedUint8
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloBytes EmbedBytes
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloString EmbedString
|
||||
)
|
||||
|
||||
type T byte
|
||||
type EmbedUint8 uint8
|
||||
type EmbedBytes []byte
|
||||
type EmbedString string
|
||||
|
||||
// golang.org/issue/47735
|
||||
func TestAliases(t *testing.T) {
|
||||
all := testDirAll
|
||||
want, e := all.ReadFile("testdata/hello.txt")
|
||||
if e != nil {
|
||||
t.Fatal("ReadFile:", e)
|
||||
}
|
||||
check := func(g interface{}) {
|
||||
got := reflect.ValueOf(g)
|
||||
for i := 0; i < got.Len(); i++ {
|
||||
if byte(got.Index(i).Uint()) != want[i] {
|
||||
t.Fatalf("got %v want %v", got.Bytes(), want)
|
||||
}
|
||||
}
|
||||
}
|
||||
check(helloT)
|
||||
check(helloUint8)
|
||||
check(helloEUint8)
|
||||
check(helloBytes)
|
||||
check(helloString)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ go 1.17
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed
|
||||
golang.org/x/net v0.0.0-20211209100829-84cba5454caf
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
|
||||
golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f // indirect
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209100829-84cba5454caf h1:Chci/BE/+xVqrcWnObL99NS8gtXyJrhHDlygBQrggHM=
|
||||
golang.org/x/net v0.0.0-20211209100829-84cba5454caf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q=
|
||||
|
||||
@@ -224,7 +224,6 @@ func (check *Checker) exprList(elist []ast.Expr, allowCommaOk bool) (xlist []*op
|
||||
// exactly one (possibly invalid or comma-ok) value
|
||||
xlist = []*operand{&x}
|
||||
if allowCommaOk && (x.mode == mapindex || x.mode == commaok || x.mode == commaerr) {
|
||||
x.mode = value
|
||||
x2 := &operand{mode: value, expr: e, typ: Typ[UntypedBool]}
|
||||
if x.mode == commaerr {
|
||||
x2.typ = universeError
|
||||
|
||||
@@ -343,6 +343,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
|
||||
if tn == t.obj {
|
||||
check.cycleError(path[i:])
|
||||
t.info = invalid
|
||||
t.underlying = Typ[Invalid]
|
||||
return t.info
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ func (check *Checker) collectObjects() {
|
||||
}
|
||||
|
||||
if name == "init" {
|
||||
check.errorf(d.spec.Name, _InvalidInitDecl, "cannot import package as init - init must be a func")
|
||||
check.errorf(d.spec, _InvalidInitDecl, "cannot import package as init - init must be a func")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
15
src/go/types/testdata/fixedbugs/issue48819.src
vendored
Normal file
15
src/go/types/testdata/fixedbugs/issue48819.src
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type T /* ERROR illegal cycle in declaration of T */ struct {
|
||||
T
|
||||
}
|
||||
|
||||
func _(t T) {
|
||||
_ = unsafe.Sizeof(t) // should not go into infinite recursion here
|
||||
}
|
||||
@@ -759,6 +759,9 @@ func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *_TypeP
|
||||
|
||||
func (t *_TypeParam) Bound() *Interface {
|
||||
iface := asInterface(t.bound)
|
||||
if iface == nil {
|
||||
return &emptyInterface
|
||||
}
|
||||
// use the type bound position if we have one
|
||||
pos := token.NoPos
|
||||
if n, _ := t.bound.(*Named); n != nil {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin && !ios
|
||||
// +build darwin,!ios
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
|
||||
@@ -965,7 +965,6 @@ func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
|
||||
if err == nil {
|
||||
return n, nil
|
||||
}
|
||||
b.stop()
|
||||
if err == io.EOF {
|
||||
return n, err
|
||||
}
|
||||
|
||||
@@ -1353,6 +1353,33 @@ func TestClientTimeoutCancel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientTimeoutDoesNotExpire_h1(t *testing.T) { testClientTimeoutDoesNotExpire(t, h1Mode) }
|
||||
func TestClientTimeoutDoesNotExpire_h2(t *testing.T) { testClientTimeoutDoesNotExpire(t, h2Mode) }
|
||||
|
||||
// Issue 49366: if Client.Timeout is set but not hit, no error should be returned.
|
||||
func testClientTimeoutDoesNotExpire(t *testing.T, h2 bool) {
|
||||
setParallel(t)
|
||||
defer afterTest(t)
|
||||
|
||||
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
w.Write([]byte("body"))
|
||||
}))
|
||||
defer cst.close()
|
||||
|
||||
cst.c.Timeout = 1 * time.Hour
|
||||
req, _ := NewRequest("GET", cst.ts.URL, nil)
|
||||
res, err := cst.c.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = io.Copy(io.Discard, res.Body); err != nil {
|
||||
t.Fatalf("io.Copy(io.Discard, res.Body) = %v, want nil", err)
|
||||
}
|
||||
if err = res.Body.Close(); err != nil {
|
||||
t.Fatalf("res.Body.Close() = %v, want nil", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientRedirectEatsBody_h1(t *testing.T) { testClientRedirectEatsBody(t, h1Mode) }
|
||||
func TestClientRedirectEatsBody_h2(t *testing.T) { testClientRedirectEatsBody(t, h2Mode) }
|
||||
func testClientRedirectEatsBody(t *testing.T, h2 bool) {
|
||||
|
||||
@@ -1582,3 +1582,37 @@ func TestH12_WebSocketUpgrade(t *testing.T) {
|
||||
},
|
||||
}.run(t)
|
||||
}
|
||||
|
||||
func TestIdentityTransferEncoding_h1(t *testing.T) { testIdentityTransferEncoding(t, h1Mode) }
|
||||
func TestIdentityTransferEncoding_h2(t *testing.T) { testIdentityTransferEncoding(t, h2Mode) }
|
||||
|
||||
func testIdentityTransferEncoding(t *testing.T, h2 bool) {
|
||||
setParallel(t)
|
||||
defer afterTest(t)
|
||||
|
||||
const body = "body"
|
||||
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
gotBody, _ := io.ReadAll(r.Body)
|
||||
if got, want := string(gotBody), body; got != want {
|
||||
t.Errorf("got request body = %q; want %q", got, want)
|
||||
}
|
||||
w.Header().Set("Transfer-Encoding", "identity")
|
||||
w.WriteHeader(StatusOK)
|
||||
w.(Flusher).Flush()
|
||||
io.WriteString(w, body)
|
||||
}))
|
||||
defer cst.close()
|
||||
req, _ := NewRequest("GET", cst.ts.URL, strings.NewReader(body))
|
||||
res, err := cst.c.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
gotBody, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := string(gotBody), body; got != want {
|
||||
t.Errorf("got response body = %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1404,11 +1404,11 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
||||
hasCL = false
|
||||
}
|
||||
|
||||
if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) {
|
||||
// do nothing
|
||||
} else if code == StatusNoContent {
|
||||
if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) || code == StatusNoContent {
|
||||
// Response has no body.
|
||||
delHeader("Transfer-Encoding")
|
||||
} else if hasCL {
|
||||
// Content-Length has been provided, so no chunking is to be done.
|
||||
delHeader("Transfer-Encoding")
|
||||
} else if w.req.ProtoAtLeast(1, 1) {
|
||||
// HTTP/1.1 or greater: Transfer-Encoding has been set to identity, and no
|
||||
@@ -1419,6 +1419,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
||||
if hasTE && te == "identity" {
|
||||
cw.chunking = false
|
||||
w.closeAfterReply = true
|
||||
delHeader("Transfer-Encoding")
|
||||
} else {
|
||||
// HTTP/1.1 or greater: use chunked transfer encoding
|
||||
// to avoid closing the connection at EOF.
|
||||
|
||||
@@ -10,6 +10,7 @@ package exec_test
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"testing"
|
||||
@@ -41,3 +42,16 @@ func TestPipePassing(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoInheritHandles(t *testing.T) {
|
||||
cmd := exec.Command("cmd", "/c exit 88")
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{NoInheritHandles: true}
|
||||
err := cmd.Run()
|
||||
exitError, ok := err.(*exec.ExitError)
|
||||
if !ok {
|
||||
t.Fatalf("got error %v; want ExitError", err)
|
||||
}
|
||||
if exitError.ExitCode() != 88 {
|
||||
t.Fatalf("got exit code %d; want 88", exitError.ExitCode())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ type pollDesc struct {
|
||||
// pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO readiness notification)
|
||||
// proceed w/o taking the lock. So closing, everr, rg, rd, wg and wd are manipulated
|
||||
// in a lock-free way by all operations.
|
||||
// TODO(golang.org/issue/49008): audit these lock-free fields for continued correctness.
|
||||
// NOTE(dvyukov): the following code uses uintptr to store *g (rg/wg),
|
||||
// that will blow up when GC starts moving objects.
|
||||
lock mutex // protects the following fields
|
||||
@@ -86,11 +87,11 @@ type pollDesc struct {
|
||||
everr bool // marks event scanning error happened
|
||||
user uint32 // user settable cookie
|
||||
rseq uintptr // protects from stale read timers
|
||||
rg uintptr // pdReady, pdWait, G waiting for read or nil
|
||||
rg uintptr // pdReady, pdWait, G waiting for read or nil. Accessed atomically.
|
||||
rt timer // read deadline timer (set if rt.f != nil)
|
||||
rd int64 // read deadline
|
||||
wseq uintptr // protects from stale write timers
|
||||
wg uintptr // pdReady, pdWait, G waiting for write or nil
|
||||
wg uintptr // pdReady, pdWait, G waiting for write or nil. Accessed atomically.
|
||||
wt timer // write deadline timer
|
||||
wd int64 // write deadline
|
||||
self *pollDesc // storage for indirect interface. See (*pollDesc).makeArg.
|
||||
@@ -147,20 +148,22 @@ func poll_runtime_isPollServerDescriptor(fd uintptr) bool {
|
||||
func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
|
||||
pd := pollcache.alloc()
|
||||
lock(&pd.lock)
|
||||
if pd.wg != 0 && pd.wg != pdReady {
|
||||
wg := atomic.Loaduintptr(&pd.wg)
|
||||
if wg != 0 && wg != pdReady {
|
||||
throw("runtime: blocked write on free polldesc")
|
||||
}
|
||||
if pd.rg != 0 && pd.rg != pdReady {
|
||||
rg := atomic.Loaduintptr(&pd.rg)
|
||||
if rg != 0 && rg != pdReady {
|
||||
throw("runtime: blocked read on free polldesc")
|
||||
}
|
||||
pd.fd = fd
|
||||
pd.closing = false
|
||||
pd.everr = false
|
||||
pd.rseq++
|
||||
pd.rg = 0
|
||||
atomic.Storeuintptr(&pd.rg, 0)
|
||||
pd.rd = 0
|
||||
pd.wseq++
|
||||
pd.wg = 0
|
||||
atomic.Storeuintptr(&pd.wg, 0)
|
||||
pd.wd = 0
|
||||
pd.self = pd
|
||||
unlock(&pd.lock)
|
||||
@@ -178,10 +181,12 @@ func poll_runtime_pollClose(pd *pollDesc) {
|
||||
if !pd.closing {
|
||||
throw("runtime: close polldesc w/o unblock")
|
||||
}
|
||||
if pd.wg != 0 && pd.wg != pdReady {
|
||||
wg := atomic.Loaduintptr(&pd.wg)
|
||||
if wg != 0 && wg != pdReady {
|
||||
throw("runtime: blocked write on closing polldesc")
|
||||
}
|
||||
if pd.rg != 0 && pd.rg != pdReady {
|
||||
rg := atomic.Loaduintptr(&pd.rg)
|
||||
if rg != 0 && rg != pdReady {
|
||||
throw("runtime: blocked read on closing polldesc")
|
||||
}
|
||||
netpollclose(pd.fd)
|
||||
@@ -205,9 +210,9 @@ func poll_runtime_pollReset(pd *pollDesc, mode int) int {
|
||||
return errcode
|
||||
}
|
||||
if mode == 'r' {
|
||||
pd.rg = 0
|
||||
atomic.Storeuintptr(&pd.rg, 0)
|
||||
} else if mode == 'w' {
|
||||
pd.wg = 0
|
||||
atomic.Storeuintptr(&pd.wg, 0)
|
||||
}
|
||||
return pollNoError
|
||||
}
|
||||
@@ -417,6 +422,8 @@ func netpollgoready(gp *g, traceskip int) {
|
||||
|
||||
// returns true if IO is ready, or false if timedout or closed
|
||||
// waitio - wait only for completed IO, ignore errors
|
||||
// Concurrent calls to netpollblock in the same mode are forbidden, as pollDesc
|
||||
// can hold only a single waiting goroutine for each mode.
|
||||
func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
|
||||
gpp := &pd.rg
|
||||
if mode == 'w' {
|
||||
@@ -425,17 +432,19 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
|
||||
|
||||
// set the gpp semaphore to pdWait
|
||||
for {
|
||||
old := *gpp
|
||||
if old == pdReady {
|
||||
*gpp = 0
|
||||
// Consume notification if already ready.
|
||||
if atomic.Casuintptr(gpp, pdReady, 0) {
|
||||
return true
|
||||
}
|
||||
if old != 0 {
|
||||
throw("runtime: double wait")
|
||||
}
|
||||
if atomic.Casuintptr(gpp, 0, pdWait) {
|
||||
break
|
||||
}
|
||||
|
||||
// Double check that this isn't corrupt; otherwise we'd loop
|
||||
// forever.
|
||||
if v := atomic.Loaduintptr(gpp); v != pdReady && v != 0 {
|
||||
throw("runtime: double wait")
|
||||
}
|
||||
}
|
||||
|
||||
// need to recheck error states after setting gpp to pdWait
|
||||
@@ -459,7 +468,7 @@ func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g {
|
||||
}
|
||||
|
||||
for {
|
||||
old := *gpp
|
||||
old := atomic.Loaduintptr(gpp)
|
||||
if old == pdReady {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4686,7 +4686,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
|
||||
return
|
||||
}
|
||||
|
||||
// On mips{,le}, 64bit atomics are emulated with spinlocks, in
|
||||
// On mips{,le}/arm, 64bit atomics are emulated with spinlocks, in
|
||||
// runtime/internal/atomic. If SIGPROF arrives while the program is inside
|
||||
// the critical section, it creates a deadlock (when writing the sample).
|
||||
// As a workaround, create a counter of SIGPROFs while in critical section
|
||||
@@ -4699,6 +4699,13 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && pc&0xffff0000 == 0xffff0000 {
|
||||
// runtime/internal/atomic functions call into kernel
|
||||
// helpers on arm < 7. See
|
||||
// runtime/internal/atomic/sys_linux_arm.s.
|
||||
cpuprof.lostAtomic++
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Profiling runs concurrently with GC, so it must not allocate.
|
||||
|
||||
@@ -105,28 +105,38 @@ func syscallNoErr()
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_attr_init(attr *pthreadattr) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
return ret
|
||||
}
|
||||
func pthread_attr_init_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_attr_getstacksize(attr *pthreadattr, size *uintptr) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
KeepAlive(size)
|
||||
return ret
|
||||
}
|
||||
func pthread_attr_getstacksize_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_attr_setdetachstate(attr *pthreadattr, state int) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
return ret
|
||||
}
|
||||
func pthread_attr_setdetachstate_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_create(attr *pthreadattr, start uintptr, arg unsafe.Pointer) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_create_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_create_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
KeepAlive(arg) // Just for consistency. Arg of course needs to be kept alive for the start function.
|
||||
return ret
|
||||
}
|
||||
func pthread_create_trampoline()
|
||||
|
||||
@@ -175,6 +185,7 @@ func mmap_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func munmap(addr unsafe.Pointer, n uintptr) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(munmap_trampoline)), unsafe.Pointer(&addr))
|
||||
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
|
||||
}
|
||||
func munmap_trampoline()
|
||||
|
||||
@@ -182,6 +193,7 @@ func munmap_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(madvise_trampoline)), unsafe.Pointer(&addr))
|
||||
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
|
||||
}
|
||||
func madvise_trampoline()
|
||||
|
||||
@@ -189,13 +201,16 @@ func madvise_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func mlock(addr unsafe.Pointer, n uintptr) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(mlock_trampoline)), unsafe.Pointer(&addr))
|
||||
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
|
||||
}
|
||||
func mlock_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func read(fd int32, p unsafe.Pointer, n int32) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(read_trampoline)), unsafe.Pointer(&fd))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(read_trampoline)), unsafe.Pointer(&fd))
|
||||
KeepAlive(p)
|
||||
return ret
|
||||
}
|
||||
func read_trampoline()
|
||||
|
||||
@@ -239,14 +254,18 @@ func usleep_no_g(usec uint32) {
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func write1(fd uintptr, p unsafe.Pointer, n int32) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(write_trampoline)), unsafe.Pointer(&fd))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(write_trampoline)), unsafe.Pointer(&fd))
|
||||
KeepAlive(p)
|
||||
return ret
|
||||
}
|
||||
func write_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func open(name *byte, mode, perm int32) (ret int32) {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(open_trampoline)), unsafe.Pointer(&name))
|
||||
ret = libcCall(unsafe.Pointer(abi.FuncPCABI0(open_trampoline)), unsafe.Pointer(&name))
|
||||
KeepAlive(name)
|
||||
return
|
||||
}
|
||||
func open_trampoline()
|
||||
|
||||
@@ -285,6 +304,8 @@ func walltime_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func sigaction(sig uint32, new *usigactiont, old *usigactiont) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(sigaction_trampoline)), unsafe.Pointer(&sig))
|
||||
KeepAlive(new)
|
||||
KeepAlive(old)
|
||||
}
|
||||
func sigaction_trampoline()
|
||||
|
||||
@@ -292,6 +313,8 @@ func sigaction_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func sigprocmask(how uint32, new *sigset, old *sigset) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(sigprocmask_trampoline)), unsafe.Pointer(&how))
|
||||
KeepAlive(new)
|
||||
KeepAlive(old)
|
||||
}
|
||||
func sigprocmask_trampoline()
|
||||
|
||||
@@ -306,6 +329,8 @@ func sigaltstack(new *stackt, old *stackt) {
|
||||
new.ss_size = 32768
|
||||
}
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(sigaltstack_trampoline)), unsafe.Pointer(&new))
|
||||
KeepAlive(new)
|
||||
KeepAlive(old)
|
||||
}
|
||||
func sigaltstack_trampoline()
|
||||
|
||||
@@ -320,20 +345,32 @@ func raiseproc_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func setitimer(mode int32, new, old *itimerval) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(setitimer_trampoline)), unsafe.Pointer(&mode))
|
||||
KeepAlive(new)
|
||||
KeepAlive(old)
|
||||
}
|
||||
func setitimer_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func sysctl(mib *uint32, miblen uint32, oldp *byte, oldlenp *uintptr, newp *byte, newlen uintptr) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctl_trampoline)), unsafe.Pointer(&mib))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctl_trampoline)), unsafe.Pointer(&mib))
|
||||
KeepAlive(mib)
|
||||
KeepAlive(oldp)
|
||||
KeepAlive(oldlenp)
|
||||
KeepAlive(newp)
|
||||
return ret
|
||||
}
|
||||
func sysctl_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func sysctlbyname(name *byte, oldp *byte, oldlenp *uintptr, newp *byte, newlen uintptr) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctlbyname_trampoline)), unsafe.Pointer(&name))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctlbyname_trampoline)), unsafe.Pointer(&name))
|
||||
KeepAlive(name)
|
||||
KeepAlive(oldp)
|
||||
KeepAlive(oldlenp)
|
||||
KeepAlive(newp)
|
||||
return ret
|
||||
}
|
||||
func sysctlbyname_trampoline()
|
||||
|
||||
@@ -355,56 +392,79 @@ func kqueue_trampoline()
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(kevent_trampoline)), unsafe.Pointer(&kq))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(kevent_trampoline)), unsafe.Pointer(&kq))
|
||||
KeepAlive(ch)
|
||||
KeepAlive(ev)
|
||||
KeepAlive(ts)
|
||||
return ret
|
||||
}
|
||||
func kevent_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_mutex_init(m *pthreadmutex, attr *pthreadmutexattr) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_init_trampoline)), unsafe.Pointer(&m))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_init_trampoline)), unsafe.Pointer(&m))
|
||||
KeepAlive(m)
|
||||
KeepAlive(attr)
|
||||
return ret
|
||||
}
|
||||
func pthread_mutex_init_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_mutex_lock(m *pthreadmutex) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_lock_trampoline)), unsafe.Pointer(&m))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_lock_trampoline)), unsafe.Pointer(&m))
|
||||
KeepAlive(m)
|
||||
return ret
|
||||
}
|
||||
func pthread_mutex_lock_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_mutex_unlock(m *pthreadmutex) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_unlock_trampoline)), unsafe.Pointer(&m))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_unlock_trampoline)), unsafe.Pointer(&m))
|
||||
KeepAlive(m)
|
||||
return ret
|
||||
}
|
||||
func pthread_mutex_unlock_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_cond_init(c *pthreadcond, attr *pthreadcondattr) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_init_trampoline)), unsafe.Pointer(&c))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_init_trampoline)), unsafe.Pointer(&c))
|
||||
KeepAlive(c)
|
||||
KeepAlive(attr)
|
||||
return ret
|
||||
}
|
||||
func pthread_cond_init_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_cond_wait(c *pthreadcond, m *pthreadmutex) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_wait_trampoline)), unsafe.Pointer(&c))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_wait_trampoline)), unsafe.Pointer(&c))
|
||||
KeepAlive(c)
|
||||
KeepAlive(m)
|
||||
return ret
|
||||
}
|
||||
func pthread_cond_wait_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_cond_timedwait_relative_np(c *pthreadcond, m *pthreadmutex, t *timespec) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_timedwait_relative_np_trampoline)), unsafe.Pointer(&c))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_timedwait_relative_np_trampoline)), unsafe.Pointer(&c))
|
||||
KeepAlive(c)
|
||||
KeepAlive(m)
|
||||
KeepAlive(t)
|
||||
return ret
|
||||
}
|
||||
func pthread_cond_timedwait_relative_np_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_cond_signal(c *pthreadcond) int32 {
|
||||
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_signal_trampoline)), unsafe.Pointer(&c))
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_signal_trampoline)), unsafe.Pointer(&c))
|
||||
KeepAlive(c)
|
||||
return ret
|
||||
}
|
||||
func pthread_cond_signal_trampoline()
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@ import (
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func g0_pthread_key_create(k *pthreadkey, destructor uintptr) int32 {
|
||||
return asmcgocall(unsafe.Pointer(funcPC(pthread_key_create_trampoline)), unsafe.Pointer(&k))
|
||||
ret := asmcgocall(unsafe.Pointer(funcPC(pthread_key_create_trampoline)), unsafe.Pointer(&k))
|
||||
KeepAlive(k)
|
||||
return ret
|
||||
}
|
||||
func pthread_key_create_trampoline()
|
||||
|
||||
|
||||
@@ -15,35 +15,47 @@ import "unsafe"
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_attr_init(attr *pthreadattr) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
return ret
|
||||
}
|
||||
func pthread_attr_init_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_attr_destroy(attr *pthreadattr) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(pthread_attr_destroy_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(pthread_attr_destroy_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
return ret
|
||||
}
|
||||
func pthread_attr_destroy_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_attr_getstacksize(attr *pthreadattr, size *uintptr) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
KeepAlive(size)
|
||||
return ret
|
||||
}
|
||||
func pthread_attr_getstacksize_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_attr_setdetachstate(attr *pthreadattr, state int) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
return ret
|
||||
}
|
||||
func pthread_attr_setdetachstate_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func pthread_create(attr *pthreadattr, start uintptr, arg unsafe.Pointer) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(pthread_create_trampoline)), unsafe.Pointer(&attr))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(pthread_create_trampoline)), unsafe.Pointer(&attr))
|
||||
KeepAlive(attr)
|
||||
KeepAlive(arg) // Just for consistency. Arg of course needs to be kept alive for the start function.
|
||||
return ret
|
||||
}
|
||||
func pthread_create_trampoline()
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ import "unsafe"
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(thrsleep_trampoline)), unsafe.Pointer(&ident))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(thrsleep_trampoline)), unsafe.Pointer(&ident))
|
||||
KeepAlive(tsp)
|
||||
KeepAlive(abort)
|
||||
return ret
|
||||
}
|
||||
func thrsleep_trampoline()
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (un
|
||||
ret2 int
|
||||
}{addr, n, prot, flags, fd, off, nil, 0}
|
||||
libcCall(unsafe.Pointer(funcPC(mmap_trampoline)), unsafe.Pointer(&args))
|
||||
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
|
||||
return args.ret1, args.ret2
|
||||
}
|
||||
func mmap_trampoline()
|
||||
@@ -62,6 +63,7 @@ func mmap_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func munmap(addr unsafe.Pointer, n uintptr) {
|
||||
libcCall(unsafe.Pointer(funcPC(munmap_trampoline)), unsafe.Pointer(&addr))
|
||||
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
|
||||
}
|
||||
func munmap_trampoline()
|
||||
|
||||
@@ -69,13 +71,16 @@ func munmap_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
|
||||
libcCall(unsafe.Pointer(funcPC(madvise_trampoline)), unsafe.Pointer(&addr))
|
||||
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
|
||||
}
|
||||
func madvise_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func open(name *byte, mode, perm int32) (ret int32) {
|
||||
return libcCall(unsafe.Pointer(funcPC(open_trampoline)), unsafe.Pointer(&name))
|
||||
ret = libcCall(unsafe.Pointer(funcPC(open_trampoline)), unsafe.Pointer(&name))
|
||||
KeepAlive(name)
|
||||
return
|
||||
}
|
||||
func open_trampoline()
|
||||
|
||||
@@ -89,14 +94,18 @@ func close_trampoline()
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func read(fd int32, p unsafe.Pointer, n int32) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(read_trampoline)), unsafe.Pointer(&fd))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(read_trampoline)), unsafe.Pointer(&fd))
|
||||
KeepAlive(p)
|
||||
return ret
|
||||
}
|
||||
func read_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func write1(fd uintptr, p unsafe.Pointer, n int32) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(write_trampoline)), unsafe.Pointer(&fd))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(write_trampoline)), unsafe.Pointer(&fd))
|
||||
KeepAlive(p)
|
||||
return ret
|
||||
}
|
||||
func write_trampoline()
|
||||
|
||||
@@ -119,6 +128,8 @@ func pipe2_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func setitimer(mode int32, new, old *itimerval) {
|
||||
libcCall(unsafe.Pointer(funcPC(setitimer_trampoline)), unsafe.Pointer(&mode))
|
||||
KeepAlive(new)
|
||||
KeepAlive(old)
|
||||
}
|
||||
func setitimer_trampoline()
|
||||
|
||||
@@ -138,7 +149,12 @@ func usleep_no_g(usec uint32) {
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(sysctl_trampoline)), unsafe.Pointer(&mib))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(sysctl_trampoline)), unsafe.Pointer(&mib))
|
||||
KeepAlive(mib)
|
||||
KeepAlive(out)
|
||||
KeepAlive(size)
|
||||
KeepAlive(dst)
|
||||
return ret
|
||||
}
|
||||
func sysctl_trampoline()
|
||||
|
||||
@@ -182,7 +198,11 @@ func kqueue_trampoline()
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 {
|
||||
return libcCall(unsafe.Pointer(funcPC(kevent_trampoline)), unsafe.Pointer(&kq))
|
||||
ret := libcCall(unsafe.Pointer(funcPC(kevent_trampoline)), unsafe.Pointer(&kq))
|
||||
KeepAlive(ch)
|
||||
KeepAlive(ev)
|
||||
KeepAlive(ts)
|
||||
return ret
|
||||
}
|
||||
func kevent_trampoline()
|
||||
|
||||
@@ -190,6 +210,8 @@ func kevent_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func sigaction(sig uint32, new *sigactiont, old *sigactiont) {
|
||||
libcCall(unsafe.Pointer(funcPC(sigaction_trampoline)), unsafe.Pointer(&sig))
|
||||
KeepAlive(new)
|
||||
KeepAlive(old)
|
||||
}
|
||||
func sigaction_trampoline()
|
||||
|
||||
@@ -197,6 +219,8 @@ func sigaction_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func sigprocmask(how uint32, new *sigset, old *sigset) {
|
||||
libcCall(unsafe.Pointer(funcPC(sigprocmask_trampoline)), unsafe.Pointer(&how))
|
||||
KeepAlive(new)
|
||||
KeepAlive(old)
|
||||
}
|
||||
func sigprocmask_trampoline()
|
||||
|
||||
@@ -204,6 +228,8 @@ func sigprocmask_trampoline()
|
||||
//go:cgo_unsafe_args
|
||||
func sigaltstack(new *stackt, old *stackt) {
|
||||
libcCall(unsafe.Pointer(funcPC(sigaltstack_trampoline)), unsafe.Pointer(&new))
|
||||
KeepAlive(new)
|
||||
KeepAlive(old)
|
||||
}
|
||||
func sigaltstack_trampoline()
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$8-12
|
||||
MOVQ 0(SP), AX
|
||||
|
||||
// generated code for
|
||||
// func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
|
||||
// func f(x uint64) (uint64, uint64) { return x/1000000000, x%1000000000 }
|
||||
// adapted to reduce duplication
|
||||
MOVQ AX, CX
|
||||
MOVQ $1360296554856532783, AX
|
||||
|
||||
@@ -348,16 +348,9 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
|
||||
CMPB runtime·useQPCTime(SB), $0
|
||||
JNE useQPC
|
||||
MOVQ $_INTERRUPT_TIME, DI
|
||||
loop:
|
||||
MOVL time_hi1(DI), AX
|
||||
MOVL time_lo(DI), BX
|
||||
MOVL time_hi2(DI), CX
|
||||
CMPL AX, CX
|
||||
JNE loop
|
||||
SHLQ $32, CX
|
||||
ORQ BX, CX
|
||||
IMULQ $100, CX
|
||||
MOVQ CX, ret+0(FP)
|
||||
MOVQ time_lo(DI), AX
|
||||
IMULQ $100, AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
useQPC:
|
||||
JMP runtime·nanotimeQPC(SB)
|
||||
|
||||
@@ -350,7 +350,9 @@ TEXT runtime·nanotime1(SB),NOSPLIT|NOFRAME,$0-8
|
||||
MOVW $_INTERRUPT_TIME, R3
|
||||
loop:
|
||||
MOVW time_hi1(R3), R1
|
||||
DMB MB_ISH
|
||||
MOVW time_lo(R3), R0
|
||||
DMB MB_ISH
|
||||
MOVW time_hi2(R3), R2
|
||||
CMP R1, R2
|
||||
BNE loop
|
||||
|
||||
@@ -415,15 +415,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT|NOFRAME,$0-8
|
||||
CMP $0, R0
|
||||
BNE useQPC
|
||||
MOVD $_INTERRUPT_TIME, R3
|
||||
loop:
|
||||
MOVWU time_hi1(R3), R1
|
||||
MOVWU time_lo(R3), R0
|
||||
MOVWU time_hi2(R3), R2
|
||||
CMP R1, R2
|
||||
BNE loop
|
||||
|
||||
// wintime = R1:R0, multiply by 100
|
||||
ORR R1<<32, R0
|
||||
MOVD time_lo(R3), R0
|
||||
MOVD $100, R1
|
||||
MUL R1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
|
||||
@@ -303,6 +303,8 @@ func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe.
|
||||
entersyscallblock()
|
||||
asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&call))
|
||||
exitsyscall()
|
||||
KeepAlive(wstatus)
|
||||
KeepAlive(rusage)
|
||||
return int(call.r1), call.err
|
||||
}
|
||||
|
||||
|
||||
@@ -422,6 +422,8 @@ func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (hand
|
||||
}
|
||||
|
||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
||||
KeepAlive(filename)
|
||||
KeepAlive(absoluteFilepath)
|
||||
handle = c.r1
|
||||
if handle == 0 {
|
||||
err = c.err
|
||||
@@ -441,6 +443,7 @@ func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
|
||||
c.n = 1
|
||||
c.args = uintptr(noescape(unsafe.Pointer(&filename)))
|
||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
||||
KeepAlive(filename)
|
||||
handle = c.r1
|
||||
if handle == 0 {
|
||||
err = c.err
|
||||
@@ -459,6 +462,7 @@ func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uint
|
||||
c.n = 2
|
||||
c.args = uintptr(noescape(unsafe.Pointer(&handle)))
|
||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
||||
KeepAlive(procname)
|
||||
outhandle = c.r1
|
||||
if outhandle == 0 {
|
||||
err = c.err
|
||||
|
||||
@@ -366,9 +366,9 @@ func deltimer(t *timer) bool {
|
||||
|
||||
// dodeltimer removes timer i from the current P's heap.
|
||||
// We are locked on the P when this is called.
|
||||
// It reports whether it saw no problems due to races.
|
||||
// It returns the smallest changed index in pp.timers.
|
||||
// The caller must have locked the timers for pp.
|
||||
func dodeltimer(pp *p, i int) {
|
||||
func dodeltimer(pp *p, i int) int {
|
||||
if t := pp.timers[i]; t.pp.ptr() != pp {
|
||||
throw("dodeltimer: wrong P")
|
||||
} else {
|
||||
@@ -380,16 +380,18 @@ func dodeltimer(pp *p, i int) {
|
||||
}
|
||||
pp.timers[last] = nil
|
||||
pp.timers = pp.timers[:last]
|
||||
smallestChanged := i
|
||||
if i != last {
|
||||
// Moving to i may have moved the last timer to a new parent,
|
||||
// so sift up to preserve the heap guarantee.
|
||||
siftupTimer(pp.timers, i)
|
||||
smallestChanged = siftupTimer(pp.timers, i)
|
||||
siftdownTimer(pp.timers, i)
|
||||
}
|
||||
if i == 0 {
|
||||
updateTimer0When(pp)
|
||||
}
|
||||
atomic.Xadd(&pp.numTimers, -1)
|
||||
return smallestChanged
|
||||
}
|
||||
|
||||
// dodeltimer0 removes timer 0 from the current P's heap.
|
||||
@@ -674,13 +676,14 @@ func adjusttimers(pp *p, now int64) {
|
||||
switch s := atomic.Load(&t.status); s {
|
||||
case timerDeleted:
|
||||
if atomic.Cas(&t.status, s, timerRemoving) {
|
||||
dodeltimer(pp, i)
|
||||
changed := dodeltimer(pp, i)
|
||||
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
|
||||
badTimer()
|
||||
}
|
||||
atomic.Xadd(&pp.deletedTimers, -1)
|
||||
// Look at this heap position again.
|
||||
i--
|
||||
// Go back to the earliest changed heap entry.
|
||||
// "- 1" because the loop will add 1.
|
||||
i = changed - 1
|
||||
}
|
||||
case timerModifiedEarlier, timerModifiedLater:
|
||||
if atomic.Cas(&t.status, s, timerMoving) {
|
||||
@@ -690,10 +693,11 @@ func adjusttimers(pp *p, now int64) {
|
||||
// We don't add it back yet because the
|
||||
// heap manipulation could cause our
|
||||
// loop to skip some other timer.
|
||||
dodeltimer(pp, i)
|
||||
changed := dodeltimer(pp, i)
|
||||
moved = append(moved, t)
|
||||
// Look at this heap position again.
|
||||
i--
|
||||
// Go back to the earliest changed heap entry.
|
||||
// "- 1" because the loop will add 1.
|
||||
i = changed - 1
|
||||
}
|
||||
case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving:
|
||||
badTimer()
|
||||
@@ -1043,7 +1047,10 @@ func timeSleepUntil() (int64, *p) {
|
||||
// "panic holding locks" message. Instead, we panic while not
|
||||
// holding a lock.
|
||||
|
||||
func siftupTimer(t []*timer, i int) {
|
||||
// siftupTimer puts the timer at position i in the right place
|
||||
// in the heap by moving it up toward the top of the heap.
|
||||
// It returns the smallest changed index.
|
||||
func siftupTimer(t []*timer, i int) int {
|
||||
if i >= len(t) {
|
||||
badTimer()
|
||||
}
|
||||
@@ -1063,8 +1070,11 @@ func siftupTimer(t []*timer, i int) {
|
||||
if tmp != t[i] {
|
||||
t[i] = tmp
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// siftdownTimer puts the timer at position i in the right place
|
||||
// in the heap by moving it down toward the bottom of the heap.
|
||||
func siftdownTimer(t []*timer, i int) {
|
||||
n := len(t)
|
||||
if i >= n {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// http://web.archive.org/web/20210411000829/https://wrkhpi.wordpress.com/2007/08/09/getting-os-information-the-kuser_shared_data-structure/
|
||||
|
||||
// Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
|
||||
// Or, on 64-bit, just read lo:hi1 all at once atomically.
|
||||
#define _INTERRUPT_TIME 0x7ffe0008
|
||||
#define _SYSTEM_TIME 0x7ffe0014
|
||||
#define time_lo 0
|
||||
|
||||
@@ -12,33 +12,20 @@
|
||||
TEXT time·now(SB),NOSPLIT,$0-24
|
||||
CMPB runtime·useQPCTime(SB), $0
|
||||
JNE useQPC
|
||||
|
||||
MOVQ $_INTERRUPT_TIME, DI
|
||||
loop:
|
||||
MOVL time_hi1(DI), AX
|
||||
MOVL time_lo(DI), BX
|
||||
MOVL time_hi2(DI), CX
|
||||
CMPL AX, CX
|
||||
JNE loop
|
||||
SHLQ $32, AX
|
||||
ORQ BX, AX
|
||||
MOVQ time_lo(DI), AX
|
||||
IMULQ $100, AX
|
||||
MOVQ AX, mono+16(FP)
|
||||
|
||||
MOVQ $_SYSTEM_TIME, DI
|
||||
wall:
|
||||
MOVL time_hi1(DI), AX
|
||||
MOVL time_lo(DI), BX
|
||||
MOVL time_hi2(DI), CX
|
||||
CMPL AX, CX
|
||||
JNE wall
|
||||
SHLQ $32, AX
|
||||
ORQ BX, AX
|
||||
MOVQ time_lo(DI), AX
|
||||
MOVQ $116444736000000000, DI
|
||||
SUBQ DI, AX
|
||||
IMULQ $100, AX
|
||||
|
||||
// generated code for
|
||||
// func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
|
||||
// func f(x uint64) (uint64, uint64) { return x/1000000000, x%1000000000 }
|
||||
// adapted to reduce duplication
|
||||
MOVQ AX, CX
|
||||
MOVQ $1360296554856532783, AX
|
||||
|
||||
@@ -17,7 +17,9 @@ TEXT time·now(SB),NOSPLIT|NOFRAME,$0-20
|
||||
MOVW $_INTERRUPT_TIME, R3
|
||||
loop:
|
||||
MOVW time_hi1(R3), R1
|
||||
DMB MB_ISH
|
||||
MOVW time_lo(R3), R0
|
||||
DMB MB_ISH
|
||||
MOVW time_hi2(R3), R2
|
||||
CMP R1, R2
|
||||
BNE loop
|
||||
@@ -34,7 +36,9 @@ loop:
|
||||
MOVW $_SYSTEM_TIME, R3
|
||||
wall:
|
||||
MOVW time_hi1(R3), R1
|
||||
DMB MB_ISH
|
||||
MOVW time_lo(R3), R0
|
||||
DMB MB_ISH
|
||||
MOVW time_hi2(R3), R2
|
||||
CMP R1, R2
|
||||
BNE wall
|
||||
|
||||
@@ -13,34 +13,18 @@ TEXT time·now(SB),NOSPLIT|NOFRAME,$0-24
|
||||
MOVB runtime·useQPCTime(SB), R0
|
||||
CMP $0, R0
|
||||
BNE useQPC
|
||||
MOVD $_INTERRUPT_TIME, R3
|
||||
loop:
|
||||
MOVWU time_hi1(R3), R1
|
||||
MOVWU time_lo(R3), R0
|
||||
MOVWU time_hi2(R3), R2
|
||||
CMP R1, R2
|
||||
BNE loop
|
||||
|
||||
// wintime = R1:R0, multiply by 100
|
||||
ORR R1<<32, R0
|
||||
MOVD $_INTERRUPT_TIME, R3
|
||||
MOVD time_lo(R3), R0
|
||||
MOVD $100, R1
|
||||
MUL R1, R0
|
||||
MOVD R0, mono+16(FP)
|
||||
|
||||
MOVD $_SYSTEM_TIME, R3
|
||||
wall:
|
||||
MOVWU time_hi1(R3), R1
|
||||
MOVWU time_lo(R3), R0
|
||||
MOVWU time_hi2(R3), R2
|
||||
CMP R1, R2
|
||||
BNE wall
|
||||
|
||||
// w = R1:R0 in 100ns units
|
||||
MOVD time_lo(R3), R0
|
||||
// convert to Unix epoch (but still 100ns units)
|
||||
#define delta 116444736000000000
|
||||
ORR R1<<32, R0
|
||||
SUB $delta, R0
|
||||
|
||||
// Convert to nSec
|
||||
MOVD $100, R1
|
||||
MUL R1, R0
|
||||
@@ -48,17 +32,14 @@ wall:
|
||||
// Code stolen from compiler output for:
|
||||
//
|
||||
// var x uint64
|
||||
// func f() (sec uint64, nsec uint32) { return x / 1000000000, uint32(x % 100000000) }
|
||||
// func f() (sec uint64, nsec uint32) { return x / 1000000000, uint32(x % 1000000000) }
|
||||
//
|
||||
LSR $1, R0, R1
|
||||
MOVD $-8543223759426509416, R2
|
||||
UMULH R2, R1, R1
|
||||
UMULH R1, R2, R1
|
||||
LSR $28, R1, R1
|
||||
MOVD R1, sec+0(FP)
|
||||
MOVD $-6067343680855748867, R1
|
||||
UMULH R0, R1, R1
|
||||
LSR $26, R1, R1
|
||||
MOVD $100000000, R2
|
||||
MOVD $1000000000, R2
|
||||
MSUB R1, R0, R2, R0
|
||||
MOVW R0, nsec+8(FP)
|
||||
RET
|
||||
|
||||
@@ -126,7 +126,7 @@ func (v *Value) Swap(new interface{}) (old interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// CompareAndSwapPointer executes the compare-and-swap operation for the Value.
|
||||
// CompareAndSwap executes the compare-and-swap operation for the Value.
|
||||
//
|
||||
// All calls to CompareAndSwap for a given Value must use values of the same
|
||||
// concrete type. CompareAndSwap of an inconsistent type panics, as does
|
||||
|
||||
@@ -153,9 +153,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
|
||||
sys = &zeroSysProcAttr
|
||||
}
|
||||
|
||||
p[0] = -1
|
||||
p[1] = -1
|
||||
|
||||
// Convert args to C form.
|
||||
argv0p, err := BytePtrFromString(argv0)
|
||||
if err != nil {
|
||||
@@ -205,14 +202,17 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
|
||||
|
||||
// Allocate child status pipe close on exec.
|
||||
if err = forkExecPipe(p[:]); err != nil {
|
||||
goto error
|
||||
ForkLock.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Kick off child.
|
||||
pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
|
||||
if err1 != 0 {
|
||||
err = Errno(err1)
|
||||
goto error
|
||||
Close(p[0])
|
||||
Close(p[1])
|
||||
ForkLock.Unlock()
|
||||
return 0, Errno(err1)
|
||||
}
|
||||
ForkLock.Unlock()
|
||||
|
||||
@@ -244,14 +244,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
|
||||
|
||||
// Read got EOF, so pipe closed on exec, so exec succeeded.
|
||||
return pid, nil
|
||||
|
||||
error:
|
||||
if p[0] >= 0 {
|
||||
Close(p[0])
|
||||
Close(p[1])
|
||||
}
|
||||
ForkLock.Unlock()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Combination of fork and exec, careful to be thread safe.
|
||||
|
||||
@@ -390,8 +390,10 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
|
||||
}
|
||||
fd = fd[:j]
|
||||
|
||||
willInheritHandles := len(fd) > 0 && !sys.NoInheritHandles
|
||||
|
||||
// Do not accidentally inherit more than these handles.
|
||||
if len(fd) > 0 {
|
||||
if willInheritHandles {
|
||||
err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
@@ -401,9 +403,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
|
||||
pi := new(ProcessInformation)
|
||||
flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT
|
||||
if sys.Token != 0 {
|
||||
err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
|
||||
err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
|
||||
} else {
|
||||
err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
|
||||
err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
|
||||
@@ -64,8 +64,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe(&pp)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -96,8 +96,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var q [2]int32
|
||||
err = pipe(&q)
|
||||
p[0] = int(q[0])
|
||||
p[1] = int(q[1])
|
||||
if err == nil {
|
||||
p[0] = int(q[0])
|
||||
p[1] = int(q[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -96,8 +96,11 @@ func Pipe(p []int) (err error) {
|
||||
if len(p) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
p[0], p[1], err = pipe()
|
||||
return
|
||||
r, w, err := pipe()
|
||||
if err == nil {
|
||||
p[0], p[1] = r, w
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//sysnb pipe2(p *[2]_C_int, flags int) (r int, w int, err error)
|
||||
@@ -109,7 +112,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
var pp [2]_C_int
|
||||
// pipe2 on dragonfly takes an fds array as an argument, but still
|
||||
// returns the file descriptors.
|
||||
p[0], p[1], err = pipe2(&pp, flags)
|
||||
r, w, err := pipe2(&pp, flags)
|
||||
if err == nil {
|
||||
p[0], p[1] = r, w
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -105,8 +105,10 @@ func Pipe2(p []int, flags int) error {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err := pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe(&pp)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,8 +45,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -118,8 +118,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe(&pp)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -131,8 +133,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,10 @@ func Pipe(p []int) (err error) {
|
||||
if err == ENOSYS {
|
||||
err = pipe(&pp)
|
||||
}
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -47,8 +49,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -152,8 +152,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, 0)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -165,8 +167,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -109,8 +109,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, 0)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -122,8 +124,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -120,8 +120,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -131,8 +133,11 @@ func Pipe(p []int) (err error) {
|
||||
if len(p) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
p[0], p[1], err = pipe()
|
||||
return
|
||||
r, w, err := pipe()
|
||||
if err == nil {
|
||||
p[0], p[1] = r, w
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
|
||||
|
||||
@@ -88,8 +88,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, 0)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,8 +103,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -155,8 +155,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, 0)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -168,8 +170,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -80,8 +80,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, 0)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -93,8 +95,10 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -112,8 +112,10 @@ func Pipe2(p []int, flags int) error {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err := pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -72,8 +72,10 @@ func Pipe2(p []int, flags int) error {
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err := pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -198,8 +198,10 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
var pp [2]int32
|
||||
err = pipe(&pp)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
if err == nil {
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,9 @@ func Pipe(p []int) (err error) {
|
||||
if e1 != 0 {
|
||||
err = Errno(e1)
|
||||
}
|
||||
p[0], p[1] = int(r0), int(w0)
|
||||
if err == nil {
|
||||
p[0], p[1] = int(r0), int(w0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user