mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] all: merge master (d0c0dc682c) into dev.regabi
Change-Id: Ia54d7306ca7550b8d5623f505070558d275faa23
This commit is contained in:
commit
6e30fc10fc
116 changed files with 2073 additions and 594 deletions
103
doc/go1.16.html
103
doc/go1.16.html
|
|
@ -80,17 +80,16 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
|
||||
<h3 id="go-command">Go command</h3>
|
||||
|
||||
<p>
|
||||
TODO
|
||||
|
||||
<!-- CL 237697: https://golang.org/cl/237697: cmd/go: error when -c or -i are used with unknown flags -->
|
||||
<!-- CL 255052: https://golang.org/cl/255052: cmd/go: default to GO111MODULE=on -->
|
||||
<!-- CL 266420: https://golang.org/cl/266420: yes (mention go help vcs): cmd/go: add GOVCS setting to control version control usage -->
|
||||
<!-- CL 244773: https://golang.org/cl/244773: cmd/go/internal/modload: drop requirements on excluded versions -->
|
||||
</p>
|
||||
|
||||
<h4 id="modules">Modules</h4>
|
||||
|
||||
<p><!-- golang.org/issue/41330 -->
|
||||
Module-aware mode is enabled by default, regardless of whether a
|
||||
<code>go.mod</code> file is present in the current working directory or a
|
||||
parent directory. Specifically, the <code>GO111MODULE</code> environment
|
||||
variable now defaults to <code>on</code>. To switch to the previous behavior,
|
||||
set <code>GO111MODULE</code> to <code>auto</code>.
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/40728 -->
|
||||
Build commands like <code>go</code> <code>build</code> and <code>go</code>
|
||||
<code>test</code> no longer modify <code>go.mod</code> and <code>go.sum</code>
|
||||
|
|
@ -107,9 +106,7 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<code>install</code> to build and install packages in module-aware mode,
|
||||
ignoring the <code>go.mod</code> file in the current directory or any parent
|
||||
directory, if there is one. This is useful for installing executables without
|
||||
affecting the dependencies of the main module.<br>
|
||||
TODO: write and link to section in golang.org/ref/mod<br>
|
||||
TODO: write and link to blog post
|
||||
affecting the dependencies of the main module.
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/40276 -->
|
||||
|
|
@ -127,8 +124,6 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
to indicate that certain published versions of the module should not be used
|
||||
by other modules. A module author may retract a version after a severe problem
|
||||
is discovered or if the version was published unintentionally.<br>
|
||||
TODO: write and link to section in golang.org/ref/mod<br>
|
||||
TODO: write and link to tutorial or blog post
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/26603 -->
|
||||
|
|
@ -138,6 +133,14 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
resolving missing packages.
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/36465 -->
|
||||
The <code>go</code> command now ignores requirements on module versions
|
||||
excluded by <code>exclude</code> directives in the main module. Previously,
|
||||
the <code>go</code> command used the next version higher than an excluded
|
||||
version, but that version could change over time, resulting in
|
||||
non-reproducible builds.
|
||||
</p>
|
||||
|
||||
<h4 id="go-test"><code>go</code> <code>test</code></h4>
|
||||
|
||||
<p><!-- golang.org/issue/29062 -->
|
||||
|
|
@ -150,6 +153,15 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
that is still considered to be a passing test.
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/39484 -->
|
||||
<code>go</code> <code>test</code> reports an error when the <code>-c</code>
|
||||
or <code>-i</code> flags are used together with unknown flags. Normally,
|
||||
unknown flags are passed to tests, but when <code>-c</code> or <code>-i</code>
|
||||
are used, tests are not run.
|
||||
</p>
|
||||
|
||||
<h4 id="go-get"><code>go</code> <code>get</code></h4>
|
||||
|
||||
<p><!-- golang.org/issue/37519 -->
|
||||
The <code>go</code> <code>get</code> <code>-insecure</code> flag is
|
||||
deprecated and will be removed in a future version. This flag permits
|
||||
|
|
@ -161,8 +173,6 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
See <code>go</code> <code>help</code> <code>environment</code> for details.
|
||||
</p>
|
||||
|
||||
<h4 id="go-get"><code>go</code> <code>get</code></h4>
|
||||
|
||||
<p><!-- golang.org/cl/263267 -->
|
||||
<code>go</code> <code>get</code> <code>example.com/mod@patch</code> now
|
||||
requires that some version of <code>example.com/mod</code> already be
|
||||
|
|
@ -171,6 +181,21 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
to patch even newly-added dependencies.)
|
||||
</p>
|
||||
|
||||
<h4 id="govcs"><code>GOVCS</code> environment variable</h4>
|
||||
|
||||
<p><!-- golang.org/issue/266420 -->
|
||||
<code>GOVCS</code> is a new environment variable that limits which version
|
||||
control tools the <code>go</code> command may use to download source code.
|
||||
This mitigates security issues with tools that are typically used in trusted,
|
||||
authenticated environments. By default, <code>git</code> and <code>hg</code>
|
||||
may be used to download code from any repository. <code>svn</code>,
|
||||
<code>bzr</code>, and <code>fossil</code> may only be used to download code
|
||||
from repositories with module paths or package paths matching patterns in
|
||||
the <code>GOPRIVATE</code> environment variable. See
|
||||
<a href="/cmd/go/#hdr-Controlling_version_control_with_GOVCS"><code>go</code>
|
||||
<code>help</code> <code>vcs</code></a> for details.
|
||||
</p>
|
||||
|
||||
<h4 id="all-pattern">The <code>all</code> pattern</h4>
|
||||
|
||||
<p><!-- golang.org/cl/240623 -->
|
||||
|
|
@ -380,7 +405,8 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
</p>
|
||||
|
||||
<p><!-- CL 246637 -->
|
||||
TODO: <a href="https://golang.org/cl/246637">https://golang.org/cl/246637</a>: make config.Clone return nil if the source is nil
|
||||
<a href="/pkg/crypto/tls/#Config.Clone"><code>Config.Clone</code></a> now returns
|
||||
a nil <code>*Config</code> if the source is nil, rather than panicking.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/tls -->
|
||||
|
|
@ -416,7 +442,9 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
</p>
|
||||
|
||||
<p><!-- CL 257257 -->
|
||||
TODO: <a href="https://golang.org/cl/257257">https://golang.org/cl/257257</a>: return additional chains from Verify on Windows
|
||||
On Windows, <a href="/pkg/crypto/x509/#Certificate.Verify"><code>Certificate.Verify</code></a>
|
||||
will now return all certificate chains that are built by the platform
|
||||
certificate verifier, instead of just the highest ranked chain.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 262343 -->
|
||||
|
|
@ -425,16 +453,26 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
</dd>
|
||||
</dl><!-- crypto/x509 -->
|
||||
|
||||
<dl id="encoding/asn1"><dt><a href="/pkg/encoding/asn1">encoding/asn1</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 255881 -->
|
||||
<a href="/pkg/encoding/asn1/#Unmarshal">Unmarshal</a> and
|
||||
<a href="/pkg/encoding/asn1/#UnmarshalWithParams">UnmarshalWithParams</a>
|
||||
now return an error instead of panic when the argument is not
|
||||
a pointer or is nil. This change matches the behavior of other
|
||||
encoding packages such as <a href="/pkg/encoding/json">encoding/json</a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="encoding/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 263619 -->
|
||||
The error message for
|
||||
<a href="/pkg/encoding/json/#SyntaxError">SyntaxError</a>
|
||||
now begins with "json: ", matching the other errors in the package.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 234818 -->
|
||||
TODO: <a href="https://golang.org/cl/234818">https://golang.org/cl/234818</a>: allow semicolon in field key / struct tag
|
||||
The <code>json</code> struct field tags understood by
|
||||
<a href="/pkg/encoding/json/#Marshal"><code>Marshal</code></a>,
|
||||
<a href="/pkg/encoding/json/#Unmarshal"><code>Unmarshal</code></a>,
|
||||
and related functionality now permit semicolon characters within
|
||||
a JSON object name for a Go struct field.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- encoding/json -->
|
||||
|
|
@ -580,7 +618,10 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 242998 -->
|
||||
TODO: <a href="https://golang.org/cl/242998">https://golang.org/cl/242998</a>: export errFinished as ErrProcessDone
|
||||
<a href="/pkg/os/#Process.Signal"><code>Process.Signal</code></a> now
|
||||
returns <a href="/pkg/os/#ErrProcessDone"><code>ErrProcessDone</code></a>
|
||||
instead of the unexported <code>errFinished</code> when the process has
|
||||
already finished.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- os -->
|
||||
|
|
@ -636,7 +677,10 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<dl id="runtime/debug"><dt><a href="/pkg/runtime/debug/">runtime/debug</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 249677 -->
|
||||
TODO: <a href="https://golang.org/cl/249677">https://golang.org/cl/249677</a>: provide Addr method for errors from SetPanicOnFault
|
||||
The <a href="/pkg/runtime#Error"><code>runtime.Error</code> values
|
||||
used when <code>SetPanicOnFault</code> is enabled may now have an
|
||||
<code>Addr</code> method. If that method exists, it returns the memory
|
||||
address that triggered the fault.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- runtime/debug -->
|
||||
|
|
@ -672,8 +716,9 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
|
||||
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 254257 -->
|
||||
TODO: <a href="https://golang.org/cl/254257">https://golang.org/cl/254257</a>: allow newlines inside action delimiters
|
||||
<p><!-- CL 254257, golang.org/issue/29770 -->
|
||||
Newlines characters are now allowed inside action delimiters,
|
||||
permitting actions to span multiple lines.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- text/template -->
|
||||
|
|
|
|||
|
|
@ -1647,14 +1647,14 @@ c := signal.Incoming()
|
|||
is
|
||||
</p>
|
||||
<pre>
|
||||
c := make(chan os.Signal)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c) // ask for all signals
|
||||
</pre>
|
||||
<p>
|
||||
but most code should list the specific signals it wants to handle instead:
|
||||
</p>
|
||||
<pre>
|
||||
c := make(chan os.Signal)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT)
|
||||
</pre>
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ func TestReader(t *testing.T) {
|
|||
for i := 0; i < len(texts)-1; i++ {
|
||||
texts[i] = str + "\n"
|
||||
all += texts[i]
|
||||
str += string(rune(i)%26 + 'a')
|
||||
str += string(rune(i%26 + 'a'))
|
||||
}
|
||||
texts[len(texts)-1] = all
|
||||
|
||||
|
|
|
|||
8
src/cmd/asm/internal/asm/testdata/riscvenc.s
vendored
8
src/cmd/asm/internal/asm/testdata/riscvenc.s
vendored
|
|
@ -340,11 +340,11 @@ start:
|
|||
// Branch pseudo-instructions
|
||||
BEQZ X5, start // BEQZ X5, 2 // e38602c0
|
||||
BGEZ X5, start // BGEZ X5, 2 // e3d402c0
|
||||
BGT X5, X6, start // BGT X5, X6, 2 // e3c262c0
|
||||
BGTU X5, X6, start // BGTU X5, X6, 2 // e3e062c0
|
||||
BGT X5, X6, start // BGT X5, X6, 2 // e34253c0
|
||||
BGTU X5, X6, start // BGTU X5, X6, 2 // e36053c0
|
||||
BGTZ X5, start // BGTZ X5, 2 // e34e50be
|
||||
BLE X5, X6, start // BLE X5, X6, 2 // e3dc62be
|
||||
BLEU X5, X6, start // BLEU X5, X6, 2 // e3fa62be
|
||||
BLE X5, X6, start // BLE X5, X6, 2 // e35c53be
|
||||
BLEU X5, X6, start // BLEU X5, X6, 2 // e37a53be
|
||||
BLEZ X5, start // BLEZ X5, 2 // e35850be
|
||||
BLTZ X5, start // BLTZ X5, 2 // e3c602be
|
||||
BNEZ X5, start // BNEZ X5, 2 // e39402be
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
f, err = os.OpenFile(file, os.O_WRONLY, 0)
|
||||
f, err = os.OpenFile(file, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import (
|
|||
"go/types"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
|
@ -89,7 +90,7 @@ func TestFormats(t *testing.T) {
|
|||
testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok
|
||||
|
||||
// process all directories
|
||||
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
filepath.WalkDir(".", func(path string, info fs.DirEntry, err error) error {
|
||||
if info.IsDir() {
|
||||
if info.Name() == "testdata" {
|
||||
return filepath.SkipDir
|
||||
|
|
|
|||
|
|
@ -790,10 +790,10 @@ func (f *Func) spSb() (sp, sb *Value) {
|
|||
}
|
||||
}
|
||||
if sb == nil {
|
||||
sb = f.Entry.NewValue0(initpos, OpSB, f.Config.Types.Uintptr)
|
||||
sb = f.Entry.NewValue0(initpos.WithNotStmt(), OpSB, f.Config.Types.Uintptr)
|
||||
}
|
||||
if sp == nil {
|
||||
sp = f.Entry.NewValue0(initpos, OpSP, f.Config.Types.Uintptr)
|
||||
sp = f.Entry.NewValue0(initpos.WithNotStmt(), OpSP, f.Config.Types.Uintptr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1369,38 +1369,38 @@
|
|||
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LT (TST x y) yes no)
|
||||
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LT (TSTconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LE (TST x y) yes no)
|
||||
(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LE (TSTconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LT (TEQ x y) yes no)
|
||||
(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LT (TEQconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LE (TEQ x y) yes no)
|
||||
(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LE (TEQconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LTnoov (TST x y) yes no)
|
||||
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LTnoov (TSTconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LEnoov (TST x y) yes no)
|
||||
(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LEnoov (TSTconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LTnoov (TEQ x y) yes no)
|
||||
(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LTnoov (TEQconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LEnoov (TEQ x y) yes no)
|
||||
(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LEnoov (TEQconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (GTnoov (CMP x y) yes no)
|
||||
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (GTnoov (CMPconst [c] x) yes no)
|
||||
|
|
@ -1436,39 +1436,39 @@
|
|||
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GT (TST x y) yes no)
|
||||
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 => (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GT (TSTconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GE (TST x y) yes no)
|
||||
(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GE (TSTconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GT (TEQ x y) yes no)
|
||||
(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GT (TEQconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GE (TEQ x y) yes no)
|
||||
(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GE (TEQconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GTnoov (TST x y) yes no)
|
||||
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TSTconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GEnoov (TST x y) yes no)
|
||||
(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TSTconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GTnoov (TEQ x y) yes no)
|
||||
(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TEQconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GEnoov (TEQ x y) yes no)
|
||||
(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TEQconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftRAreg x y z) yes no)
|
||||
|
||||
(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read8(sym, int64(off)))])
|
||||
(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])
|
||||
|
|
|
|||
|
|
@ -17389,7 +17389,7 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
// match: (GE (CMPconst [0] l:(AND x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TST x y) yes no)
|
||||
// result: (GEnoov (TST x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17410,14 +17410,14 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(ANDconst [c] x)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TSTconst [c] x) yes no)
|
||||
// result: (GEnoov (TSTconst [c] x) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17435,12 +17435,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TSTshiftLL x y [c]) yes no)
|
||||
// result: (GEnoov (TSTshiftLL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17459,12 +17459,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TSTshiftRL x y [c]) yes no)
|
||||
// result: (GEnoov (TSTshiftRL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17483,12 +17483,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TSTshiftRA x y [c]) yes no)
|
||||
// result: (GEnoov (TSTshiftRA x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17507,12 +17507,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TSTshiftLLreg x y z) yes no)
|
||||
// result: (GEnoov (TSTshiftLLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17530,12 +17530,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TSTshiftRLreg x y z) yes no)
|
||||
// result: (GEnoov (TSTshiftRLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17553,12 +17553,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TSTshiftRAreg x y z) yes no)
|
||||
// result: (GEnoov (TSTshiftRAreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17576,12 +17576,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(XOR x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TEQ x y) yes no)
|
||||
// result: (GEnoov (TEQ x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17602,14 +17602,14 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(XORconst [c] x)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TEQconst [c] x) yes no)
|
||||
// result: (GEnoov (TEQconst [c] x) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17627,12 +17627,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TEQshiftLL x y [c]) yes no)
|
||||
// result: (GEnoov (TEQshiftLL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17651,12 +17651,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TEQshiftRL x y [c]) yes no)
|
||||
// result: (GEnoov (TEQshiftRL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17675,12 +17675,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TEQshiftRA x y [c]) yes no)
|
||||
// result: (GEnoov (TEQshiftRA x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17699,12 +17699,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TEQshiftLLreg x y z) yes no)
|
||||
// result: (GEnoov (TEQshiftLLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17722,12 +17722,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TEQshiftRLreg x y z) yes no)
|
||||
// result: (GEnoov (TEQshiftRLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17745,12 +17745,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GE (TEQshiftRAreg x y z) yes no)
|
||||
// result: (GEnoov (TEQshiftRAreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -17768,7 +17768,7 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGE, v0)
|
||||
b.resetWithControl(BlockARMGEnoov, v0)
|
||||
return true
|
||||
}
|
||||
case BlockARMGEnoov:
|
||||
|
|
@ -18278,34 +18278,6 @@ func rewriteBlockARM(b *Block) bool {
|
|||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(AND x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TST x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
break
|
||||
}
|
||||
l := v_0.Args[0]
|
||||
if l.Op != OpARMAND {
|
||||
break
|
||||
}
|
||||
_ = l.Args[1]
|
||||
l_0 := l.Args[0]
|
||||
l_1 := l.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, l_0, l_1 = _i0+1, l_1, l_0 {
|
||||
x := l_0
|
||||
y := l_1
|
||||
if !(l.Uses == 1) {
|
||||
continue
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(MULA x y a)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
|
|
@ -18331,9 +18303,37 @@ func rewriteBlockARM(b *Block) bool {
|
|||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(AND x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GTnoov (TST x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
break
|
||||
}
|
||||
l := v_0.Args[0]
|
||||
if l.Op != OpARMAND {
|
||||
break
|
||||
}
|
||||
_ = l.Args[1]
|
||||
l_0 := l.Args[0]
|
||||
l_1 := l.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, l_0, l_1 = _i0+1, l_1, l_0 {
|
||||
x := l_0
|
||||
y := l_1
|
||||
if !(l.Uses == 1) {
|
||||
continue
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(ANDconst [c] x)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TSTconst [c] x) yes no)
|
||||
// result: (GTnoov (TSTconst [c] x) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18351,12 +18351,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TSTshiftLL x y [c]) yes no)
|
||||
// result: (GTnoov (TSTshiftLL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18375,12 +18375,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TSTshiftRL x y [c]) yes no)
|
||||
// result: (GTnoov (TSTshiftRL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18399,12 +18399,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TSTshiftRA x y [c]) yes no)
|
||||
// result: (GTnoov (TSTshiftRA x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18423,12 +18423,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TSTshiftLLreg x y z) yes no)
|
||||
// result: (GTnoov (TSTshiftLLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18446,12 +18446,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TSTshiftRLreg x y z) yes no)
|
||||
// result: (GTnoov (TSTshiftRLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18469,12 +18469,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TSTshiftRAreg x y z) yes no)
|
||||
// result: (GTnoov (TSTshiftRAreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18492,12 +18492,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(XOR x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TEQ x y) yes no)
|
||||
// result: (GTnoov (TEQ x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18518,14 +18518,14 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(XORconst [c] x)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TEQconst [c] x) yes no)
|
||||
// result: (GTnoov (TEQconst [c] x) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18543,12 +18543,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TEQshiftLL x y [c]) yes no)
|
||||
// result: (GTnoov (TEQshiftLL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18567,12 +18567,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TEQshiftRL x y [c]) yes no)
|
||||
// result: (GTnoov (TEQshiftRL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18591,12 +18591,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TEQshiftRA x y [c]) yes no)
|
||||
// result: (GTnoov (TEQshiftRA x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18615,12 +18615,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TEQshiftLLreg x y z) yes no)
|
||||
// result: (GTnoov (TEQshiftLLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18638,12 +18638,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TEQshiftRLreg x y z) yes no)
|
||||
// result: (GTnoov (TEQshiftRLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18661,12 +18661,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (GT (TEQshiftRAreg x y z) yes no)
|
||||
// result: (GTnoov (TEQshiftRAreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -18684,7 +18684,7 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMGT, v0)
|
||||
b.resetWithControl(BlockARMGTnoov, v0)
|
||||
return true
|
||||
}
|
||||
case BlockARMGTnoov:
|
||||
|
|
@ -19312,7 +19312,7 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
// match: (LE (CMPconst [0] l:(AND x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TST x y) yes no)
|
||||
// result: (LEnoov (TST x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19333,14 +19333,14 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(ANDconst [c] x)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TSTconst [c] x) yes no)
|
||||
// result: (LEnoov (TSTconst [c] x) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19358,12 +19358,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TSTshiftLL x y [c]) yes no)
|
||||
// result: (LEnoov (TSTshiftLL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19382,12 +19382,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TSTshiftRL x y [c]) yes no)
|
||||
// result: (LEnoov (TSTshiftRL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19406,12 +19406,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TSTshiftRA x y [c]) yes no)
|
||||
// result: (LEnoov (TSTshiftRA x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19430,12 +19430,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TSTshiftLLreg x y z) yes no)
|
||||
// result: (LEnoov (TSTshiftLLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19453,12 +19453,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TSTshiftRLreg x y z) yes no)
|
||||
// result: (LEnoov (TSTshiftRLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19476,12 +19476,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TSTshiftRAreg x y z) yes no)
|
||||
// result: (LEnoov (TSTshiftRAreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19499,12 +19499,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(XOR x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TEQ x y) yes no)
|
||||
// result: (LEnoov (TEQ x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19525,14 +19525,14 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(XORconst [c] x)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TEQconst [c] x) yes no)
|
||||
// result: (LEnoov (TEQconst [c] x) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19550,12 +19550,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TEQshiftLL x y [c]) yes no)
|
||||
// result: (LEnoov (TEQshiftLL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19574,12 +19574,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TEQshiftRL x y [c]) yes no)
|
||||
// result: (LEnoov (TEQshiftRL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19598,12 +19598,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TEQshiftRA x y [c]) yes no)
|
||||
// result: (LEnoov (TEQshiftRA x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19622,12 +19622,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TEQshiftLLreg x y z) yes no)
|
||||
// result: (LEnoov (TEQshiftLLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19645,12 +19645,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TEQshiftRLreg x y z) yes no)
|
||||
// result: (LEnoov (TEQshiftRLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19668,12 +19668,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LE (TEQshiftRAreg x y z) yes no)
|
||||
// result: (LEnoov (TEQshiftRAreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -19691,7 +19691,7 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLE, v0)
|
||||
b.resetWithControl(BlockARMLEnoov, v0)
|
||||
return true
|
||||
}
|
||||
case BlockARMLEnoov:
|
||||
|
|
@ -20228,7 +20228,7 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
// match: (LT (CMPconst [0] l:(AND x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TST x y) yes no)
|
||||
// result: (LTnoov (TST x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20249,14 +20249,14 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(ANDconst [c] x)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TSTconst [c] x) yes no)
|
||||
// result: (LTnoov (TSTconst [c] x) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20274,12 +20274,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TSTshiftLL x y [c]) yes no)
|
||||
// result: (LTnoov (TSTshiftLL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20298,12 +20298,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TSTshiftRL x y [c]) yes no)
|
||||
// result: (LTnoov (TSTshiftRL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20322,12 +20322,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TSTshiftRA x y [c]) yes no)
|
||||
// result: (LTnoov (TSTshiftRA x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20346,12 +20346,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TSTshiftLLreg x y z) yes no)
|
||||
// result: (LTnoov (TSTshiftLLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20369,12 +20369,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TSTshiftRLreg x y z) yes no)
|
||||
// result: (LTnoov (TSTshiftRLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20392,12 +20392,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TSTshiftRAreg x y z) yes no)
|
||||
// result: (LTnoov (TSTshiftRAreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20415,12 +20415,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(XOR x y)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TEQ x y) yes no)
|
||||
// result: (LTnoov (TEQ x y) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20441,14 +20441,14 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(XORconst [c] x)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TEQconst [c] x) yes no)
|
||||
// result: (LTnoov (TEQconst [c] x) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20466,12 +20466,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg(x)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TEQshiftLL x y [c]) yes no)
|
||||
// result: (LTnoov (TEQshiftLL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20490,12 +20490,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TEQshiftRL x y [c]) yes no)
|
||||
// result: (LTnoov (TEQshiftRL x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20514,12 +20514,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TEQshiftRA x y [c]) yes no)
|
||||
// result: (LTnoov (TEQshiftRA x y [c]) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20538,12 +20538,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
|
||||
v0.AuxInt = int32ToAuxInt(c)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TEQshiftLLreg x y z) yes no)
|
||||
// result: (LTnoov (TEQshiftLLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20561,12 +20561,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TEQshiftRLreg x y z) yes no)
|
||||
// result: (LTnoov (TEQshiftRLreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20584,12 +20584,12 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
|
||||
// cond: l.Uses==1
|
||||
// result: (LT (TEQshiftRAreg x y z) yes no)
|
||||
// result: (LTnoov (TEQshiftRAreg x y z) yes no)
|
||||
for b.Controls[0].Op == OpARMCMPconst {
|
||||
v_0 := b.Controls[0]
|
||||
if auxIntToInt32(v_0.AuxInt) != 0 {
|
||||
|
|
@ -20607,7 +20607,7 @@ func rewriteBlockARM(b *Block) bool {
|
|||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
|
||||
v0.AddArg3(x, y, z)
|
||||
b.resetWithControl(BlockARMLT, v0)
|
||||
b.resetWithControl(BlockARMLTnoov, v0)
|
||||
return true
|
||||
}
|
||||
case BlockARMLTnoov:
|
||||
|
|
|
|||
1
src/cmd/dist/buildtool.go
vendored
1
src/cmd/dist/buildtool.go
vendored
|
|
@ -55,6 +55,7 @@ var bootstrapDirs = []string{
|
|||
"cmd/compile/internal/x86",
|
||||
"cmd/compile/internal/wasm",
|
||||
"cmd/internal/bio",
|
||||
"cmd/internal/codesign",
|
||||
"cmd/internal/gcprog",
|
||||
"cmd/internal/dwarf",
|
||||
"cmd/internal/edit",
|
||||
|
|
|
|||
1
src/cmd/dist/test.go
vendored
1
src/cmd/dist/test.go
vendored
|
|
@ -1509,6 +1509,7 @@ func (t *tester) makeGOROOTUnwritable() (undo func()) {
|
|||
}
|
||||
gocacheSubdir, _ := filepath.Rel(dir, gocache)
|
||||
|
||||
// Note: Can't use WalkDir here, because this has to compile with Go 1.4.
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
|
||||
if suffix == gocacheSubdir {
|
||||
|
|
|
|||
|
|
@ -234,10 +234,10 @@ func report(err error) {
|
|||
}
|
||||
|
||||
func walkDir(path string) {
|
||||
filepath.Walk(path, visitFile)
|
||||
filepath.WalkDir(path, visitFile)
|
||||
}
|
||||
|
||||
func visitFile(path string, f fs.FileInfo, err error) error {
|
||||
func visitFile(path string, f fs.DirEntry, err error) error {
|
||||
if err == nil && isGoFile(f) {
|
||||
err = processFile(path, false)
|
||||
}
|
||||
|
|
@ -247,7 +247,7 @@ func visitFile(path string, f fs.FileInfo, err error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func isGoFile(f fs.FileInfo) bool {
|
||||
func isGoFile(f fs.DirEntry) bool {
|
||||
// ignore non-Go files
|
||||
name := f.Name()
|
||||
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ require (
|
|||
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
|
||||
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
|
||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
|
||||
golang.org/x/mod v0.4.0
|
||||
golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65 // indirect
|
||||
golang.org/x/tools v0.0.0-20201110201400-7099162a900a
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ=
|
||||
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
|
|
|
|||
|
|
@ -774,7 +774,7 @@ func (tg *testgoData) cleanup() {
|
|||
func removeAll(dir string) error {
|
||||
// module cache has 0444 directories;
|
||||
// make them writable in order to remove content.
|
||||
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
|
||||
filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
|
||||
// chmod not only directories, but also things that we couldn't even stat
|
||||
// due to permission errors: they may also be unreadable directories.
|
||||
if err != nil || info.IsDir() {
|
||||
|
|
@ -820,8 +820,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
|||
} {
|
||||
srcdir := filepath.Join(testGOROOT, copydir)
|
||||
tg.tempDir(filepath.Join("goroot", copydir))
|
||||
err := filepath.Walk(srcdir,
|
||||
func(path string, info fs.FileInfo, err error) error {
|
||||
err := filepath.WalkDir(srcdir,
|
||||
func(path string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -838,8 +838,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
|||
return err
|
||||
}
|
||||
tg.tempFile(dest, string(data))
|
||||
if err := os.Chmod(tg.path(dest), info.Mode()|0200); err != nil {
|
||||
return err
|
||||
if strings.Contains(copydir, filepath.Join("pkg", "tool")) {
|
||||
os.Chmod(tg.path(dest), 0777)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ var Interrupted = make(chan struct{})
|
|||
|
||||
// processSignals setups signal handler.
|
||||
func processSignals() {
|
||||
sig := make(chan os.Signal)
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, signalsToIgnore...)
|
||||
go func() {
|
||||
<-sig
|
||||
|
|
|
|||
|
|
@ -264,6 +264,9 @@ func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte,
|
|||
}
|
||||
|
||||
cmd := str.StringList(cmdline...)
|
||||
if os.Getenv("TESTGOVCS") == "panic" {
|
||||
panic(fmt.Sprintf("use of vcs: %v", cmd))
|
||||
}
|
||||
if cfg.BuildX {
|
||||
text := new(strings.Builder)
|
||||
if dir != "" {
|
||||
|
|
|
|||
|
|
@ -318,9 +318,10 @@ func makeDirsReadOnly(dir string) {
|
|||
mode fs.FileMode
|
||||
}
|
||||
var dirs []pathMode // in lexical order
|
||||
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
|
||||
if err == nil && info.Mode()&0222 != 0 {
|
||||
if info.IsDir() {
|
||||
filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err == nil && d.IsDir() {
|
||||
info, err := d.Info()
|
||||
if err == nil && info.Mode()&0222 != 0 {
|
||||
dirs = append(dirs, pathMode{path, info.Mode()})
|
||||
}
|
||||
}
|
||||
|
|
@ -337,7 +338,7 @@ func makeDirsReadOnly(dir string) {
|
|||
// any permission changes needed to do so.
|
||||
func RemoveAll(dir string) error {
|
||||
// Module cache has 0555 directories; make them writable in order to remove content.
|
||||
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
|
||||
filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return nil // ignore errors walking in file system
|
||||
}
|
||||
|
|
|
|||
|
|
@ -436,32 +436,9 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
|||
work.BuildInit()
|
||||
pkgs := load.PackagesForBuild(ctx, pkgPatterns)
|
||||
work.InstallPackages(ctx, pkgPatterns, pkgs)
|
||||
|
||||
haveExe := false
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Name == "main" {
|
||||
haveExe = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if haveExe {
|
||||
fmt.Fprint(os.Stderr, "go get: installing executables with 'go get' in module mode is deprecated.")
|
||||
var altMsg string
|
||||
if modload.HasModRoot() {
|
||||
altMsg = `
|
||||
To adjust dependencies of the current module, use 'go get -d'.
|
||||
To install using requirements of the current module, use 'go install'.
|
||||
To install ignoring the current module, use 'go install' with a version,
|
||||
like 'go install example.com/cmd@latest'.
|
||||
`
|
||||
} else {
|
||||
altMsg = "\n\tUse 'go install pkg@version' instead.\n"
|
||||
}
|
||||
fmt.Fprint(os.Stderr, altMsg)
|
||||
fmt.Fprint(os.Stderr, "\tSee 'go help get' and 'go help install' for more information.\n")
|
||||
}
|
||||
// TODO(golang.org/issue/40276): link to HTML documentation explaining
|
||||
// what's changing and gives more examples.
|
||||
// TODO(#40276): After Go 1.16, print a deprecation notice when building
|
||||
// and installing main packages. 'go install pkg' or
|
||||
// 'go install pkg@version' should be used instead.
|
||||
}
|
||||
|
||||
if !modload.HasModRoot() {
|
||||
|
|
|
|||
|
|
@ -1018,7 +1018,7 @@ func keepSums(addDirect bool) map[module.Version]bool {
|
|||
}
|
||||
}
|
||||
for _, pkg := range loaded.pkgs {
|
||||
if pkg.testOf != nil || pkg.inStd {
|
||||
if pkg.testOf != nil || pkg.inStd || module.CheckImportPath(pkg.path) != nil {
|
||||
continue
|
||||
}
|
||||
for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
"cmd/go/internal/web"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
|
|
@ -539,7 +540,7 @@ func (v *Cmd) TagSync(dir, tag string) error {
|
|||
// A vcsPath describes how to convert an import path into a
|
||||
// version control system and repository name.
|
||||
type vcsPath struct {
|
||||
prefix string // prefix this description applies to
|
||||
pathPrefix string // prefix this description applies to
|
||||
regexp *lazyregexp.Regexp // compiled pattern for import path
|
||||
repo string // repository to use (expand with match of re)
|
||||
vcs string // version control system to use (expand with match of re)
|
||||
|
|
@ -826,6 +827,20 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping")
|
|||
// repoRootFromVCSPaths attempts to map importPath to a repoRoot
|
||||
// using the mappings defined in vcsPaths.
|
||||
func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) {
|
||||
if str.HasPathPrefix(importPath, "example.net") {
|
||||
// TODO(rsc): This should not be necessary, but it's required to keep
|
||||
// tests like ../../testdata/script/mod_get_extra.txt from using the network.
|
||||
// That script has everything it needs in the replacement set, but it is still
|
||||
// doing network calls.
|
||||
return nil, fmt.Errorf("no modules on example.net")
|
||||
}
|
||||
if importPath == "rsc.io" {
|
||||
// This special case allows tests like ../../testdata/script/govcs.txt
|
||||
// to avoid making any network calls. The module lookup for a path
|
||||
// like rsc.io/nonexist.svn/foo needs to not make a network call for
|
||||
// a lookup on rsc.io.
|
||||
return nil, fmt.Errorf("rsc.io is not a module")
|
||||
}
|
||||
// A common error is to use https://packagepath because that's what
|
||||
// hg and git require. Diagnose this helpfully.
|
||||
if prefix := httpPrefix(importPath); prefix != "" {
|
||||
|
|
@ -834,20 +849,20 @@ func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths
|
|||
return nil, fmt.Errorf("%q not allowed in import path", prefix+"//")
|
||||
}
|
||||
for _, srv := range vcsPaths {
|
||||
if !strings.HasPrefix(importPath, srv.prefix) {
|
||||
if !str.HasPathPrefix(importPath, srv.pathPrefix) {
|
||||
continue
|
||||
}
|
||||
m := srv.regexp.FindStringSubmatch(importPath)
|
||||
if m == nil {
|
||||
if srv.prefix != "" {
|
||||
return nil, importErrorf(importPath, "invalid %s import path %q", srv.prefix, importPath)
|
||||
if srv.pathPrefix != "" {
|
||||
return nil, importErrorf(importPath, "invalid %s import path %q", srv.pathPrefix, importPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Build map of named subexpression matches for expand.
|
||||
match := map[string]string{
|
||||
"prefix": srv.prefix,
|
||||
"prefix": srv.pathPrefix + "/",
|
||||
"import": importPath,
|
||||
}
|
||||
for i, name := range srv.regexp.SubexpNames() {
|
||||
|
|
@ -1098,18 +1113,6 @@ type metaImport struct {
|
|||
Prefix, VCS, RepoRoot string
|
||||
}
|
||||
|
||||
// pathPrefix reports whether sub is a prefix of s,
|
||||
// only considering entire path components.
|
||||
func pathPrefix(s, sub string) bool {
|
||||
// strings.HasPrefix is necessary but not sufficient.
|
||||
if !strings.HasPrefix(s, sub) {
|
||||
return false
|
||||
}
|
||||
// The remainder after the prefix must either be empty or start with a slash.
|
||||
rem := s[len(sub):]
|
||||
return rem == "" || rem[0] == '/'
|
||||
}
|
||||
|
||||
// A ImportMismatchError is returned where metaImport/s are present
|
||||
// but none match our import path.
|
||||
type ImportMismatchError struct {
|
||||
|
|
@ -1133,7 +1136,7 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
|
|||
|
||||
errImportMismatch := ImportMismatchError{importPath: importPath}
|
||||
for i, im := range imports {
|
||||
if !pathPrefix(importPath, im.Prefix) {
|
||||
if !str.HasPathPrefix(importPath, im.Prefix) {
|
||||
errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)
|
||||
continue
|
||||
}
|
||||
|
|
@ -1175,52 +1178,52 @@ func expand(match map[string]string, s string) string {
|
|||
var vcsPaths = []*vcsPath{
|
||||
// Github
|
||||
{
|
||||
prefix: "github.com/",
|
||||
regexp: lazyregexp.New(`^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
check: noVCSSuffix,
|
||||
pathPrefix: "github.com",
|
||||
regexp: lazyregexp.New(`^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
check: noVCSSuffix,
|
||||
},
|
||||
|
||||
// Bitbucket
|
||||
{
|
||||
prefix: "bitbucket.org/",
|
||||
regexp: lazyregexp.New(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
|
||||
repo: "https://{root}",
|
||||
check: bitbucketVCS,
|
||||
pathPrefix: "bitbucket.org",
|
||||
regexp: lazyregexp.New(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
|
||||
repo: "https://{root}",
|
||||
check: bitbucketVCS,
|
||||
},
|
||||
|
||||
// IBM DevOps Services (JazzHub)
|
||||
{
|
||||
prefix: "hub.jazz.net/git/",
|
||||
regexp: lazyregexp.New(`^(?P<root>hub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
check: noVCSSuffix,
|
||||
pathPrefix: "hub.jazz.net/git",
|
||||
regexp: lazyregexp.New(`^(?P<root>hub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
check: noVCSSuffix,
|
||||
},
|
||||
|
||||
// Git at Apache
|
||||
{
|
||||
prefix: "git.apache.org/",
|
||||
regexp: lazyregexp.New(`^(?P<root>git\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
pathPrefix: "git.apache.org",
|
||||
regexp: lazyregexp.New(`^(?P<root>git\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
},
|
||||
|
||||
// Git at OpenStack
|
||||
{
|
||||
prefix: "git.openstack.org/",
|
||||
regexp: lazyregexp.New(`^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
pathPrefix: "git.openstack.org",
|
||||
regexp: lazyregexp.New(`^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
},
|
||||
|
||||
// chiselapp.com for fossil
|
||||
{
|
||||
prefix: "chiselapp.com/",
|
||||
regexp: lazyregexp.New(`^(?P<root>chiselapp\.com/user/[A-Za-z0-9]+/repository/[A-Za-z0-9_.\-]+)$`),
|
||||
vcs: "fossil",
|
||||
repo: "https://{root}",
|
||||
pathPrefix: "chiselapp.com",
|
||||
regexp: lazyregexp.New(`^(?P<root>chiselapp\.com/user/[A-Za-z0-9]+/repository/[A-Za-z0-9_.\-]+)$`),
|
||||
vcs: "fossil",
|
||||
repo: "https://{root}",
|
||||
},
|
||||
|
||||
// General syntax for any server.
|
||||
|
|
@ -1238,11 +1241,11 @@ var vcsPaths = []*vcsPath{
|
|||
var vcsPathsAfterDynamic = []*vcsPath{
|
||||
// Launchpad. See golang.org/issue/11436.
|
||||
{
|
||||
prefix: "launchpad.net/",
|
||||
regexp: lazyregexp.New(`^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "bzr",
|
||||
repo: "https://{root}",
|
||||
check: launchpadVCS,
|
||||
pathPrefix: "launchpad.net",
|
||||
regexp: lazyregexp.New(`^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "bzr",
|
||||
repo: "https://{root}",
|
||||
check: launchpadVCS,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,8 +88,15 @@ func runVersion(ctx context.Context, cmd *base.Command, args []string) {
|
|||
|
||||
// scanDir scans a directory for executables to run scanFile on.
|
||||
func scanDir(dir string) {
|
||||
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
|
||||
if info.Mode().IsRegular() || info.Mode()&fs.ModeSymlink != 0 {
|
||||
filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
||||
if d.Type().IsRegular() || d.Type()&fs.ModeSymlink != 0 {
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
if *versionV {
|
||||
fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
scanFile(path, info, *versionV)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -120,6 +127,7 @@ func scanFile(file string, info fs.FileInfo, mustPrint bool) {
|
|||
}
|
||||
info = i
|
||||
}
|
||||
|
||||
if !isExe(file, info) {
|
||||
if mustPrint {
|
||||
fmt.Fprintf(os.Stderr, "%s: not executable file\n", file)
|
||||
|
|
|
|||
|
|
@ -80,6 +80,13 @@ func get(security SecurityMode, url *urlpkg.URL) (*Response, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
if url.Host == "localhost.localdev" {
|
||||
return nil, fmt.Errorf("no such host localhost.localdev")
|
||||
}
|
||||
if os.Getenv("TESTGONETWORK") == "panic" && !strings.HasPrefix(url.Host, "127.0.0.1") && !strings.HasPrefix(url.Host, "0.0.0.0") {
|
||||
panic("use of network: " + url.String())
|
||||
}
|
||||
|
||||
fetch := func(url *urlpkg.URL) (*urlpkg.URL, *http.Response, error) {
|
||||
// Note: The -v build flag does not mean "print logging information",
|
||||
// despite its historical misuse for this in GOPATH-based go get.
|
||||
|
|
|
|||
|
|
@ -647,7 +647,7 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error {
|
|||
}
|
||||
|
||||
if rewrite {
|
||||
w, err := os.OpenFile(target, os.O_WRONLY, 0)
|
||||
w, err := os.OpenFile(target, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,9 @@ func (ts *testScript) setup() {
|
|||
"goversion=" + goVersion(ts),
|
||||
":=" + string(os.PathListSeparator),
|
||||
}
|
||||
if !testenv.HasExternalNetwork() {
|
||||
ts.env = append(ts.env, "TESTGONETWORK=panic", "TESTGOVCS=panic")
|
||||
}
|
||||
|
||||
if runtime.GOOS == "plan9" {
|
||||
ts.env = append(ts.env, "path="+testBin+string(filepath.ListSeparator)+os.Getenv("path"))
|
||||
|
|
|
|||
4
src/cmd/go/testdata/addmod.go
vendored
4
src/cmd/go/testdata/addmod.go
vendored
|
|
@ -122,8 +122,8 @@ func main() {
|
|||
{Name: ".info", Data: info},
|
||||
}
|
||||
dir = filepath.Clean(dir)
|
||||
err = filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
|
||||
if !info.Mode().IsRegular() {
|
||||
err = filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
|
||||
if !info.Type().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
name := info.Name()
|
||||
|
|
|
|||
4
src/cmd/go/testdata/savedir.go
vendored
4
src/cmd/go/testdata/savedir.go
vendored
|
|
@ -49,7 +49,7 @@ func main() {
|
|||
|
||||
a := new(txtar.Archive)
|
||||
dir = filepath.Clean(dir)
|
||||
filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
|
||||
filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
|
||||
if path == dir {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ func main() {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
if !info.Mode().IsRegular() {
|
||||
if !info.Type().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
data, err := ioutil.ReadFile(path)
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
[short] skip
|
||||
|
||||
env GO111MODULE=on
|
||||
|
||||
# 'go get' outside a module with an executable prints a deprecation message.
|
||||
go get example.com/cmd/a
|
||||
stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$'
|
||||
stderr 'Use ''go install pkg@version'' instead.'
|
||||
|
||||
|
||||
go mod init m
|
||||
|
||||
# 'go get' inside a module with a non-main package does not print a message.
|
||||
# This will stop building in the future, but it's the command we want to use.
|
||||
go get rsc.io/quote
|
||||
! stderr deprecated
|
||||
|
||||
# 'go get' inside a module with an executable prints a different
|
||||
# deprecation message.
|
||||
go get example.com/cmd/a
|
||||
stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$'
|
||||
stderr 'To adjust dependencies of the current module, use ''go get -d'''
|
||||
2
src/cmd/go/testdata/script/mod_gonoproxy.txt
vendored
2
src/cmd/go/testdata/script/mod_gonoproxy.txt
vendored
|
|
@ -21,7 +21,7 @@ go get -d rsc.io/quote
|
|||
# Download .info files needed for 'go list -m all' later.
|
||||
# TODO(#42723): either 'go list -m' should not read these files,
|
||||
# or 'go get' and 'go mod tidy' should download them.
|
||||
go list -m all
|
||||
go list -m all
|
||||
stdout '^golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c$'
|
||||
|
||||
# When GOPROXY is not empty but contains no entries, an error should be reported.
|
||||
|
|
|
|||
14
src/cmd/go/testdata/script/mod_import_issue42891.txt
vendored
Normal file
14
src/cmd/go/testdata/script/mod_import_issue42891.txt
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# If an import declaration is an absolute path, most commands should report
|
||||
# an error instead of going into an infinite loop.
|
||||
# Verifies golang.org/issue/42891.
|
||||
go list .
|
||||
stdout '^m$'
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
go 1.16
|
||||
-- m.go --
|
||||
package m
|
||||
|
||||
import "/"
|
||||
|
|
@ -2,7 +2,7 @@ env GO111MODULE=on
|
|||
env GOPROXY=$GOPROXY/invalid
|
||||
|
||||
! go list -m rsc.io/quote@latest
|
||||
stderr '^go list -m: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": json: invalid character ''i'' looking for beginning of value$'
|
||||
stderr '^go list -m: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
|
||||
|
||||
! go list -m rsc.io/quote@1.5.2
|
||||
stderr '^go list -m: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": json: invalid character ''i'' looking for beginning of value$'
|
||||
stderr '^go list -m: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ env GOPROXY=file:///$WORK/gatekeeper
|
|||
chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest
|
||||
cp go.mod.orig go.mod
|
||||
! go get -d example.com/join/subpkg
|
||||
stderr 'go get: module example.com/join/subpkg: (invalid response from proxy ".+": json: invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)'
|
||||
stderr 'go get: module example.com/join/subpkg: (invalid response from proxy ".+": invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)'
|
||||
|
||||
-- go.mod.orig --
|
||||
module example.com/othermodule
|
||||
|
|
|
|||
|
|
@ -17,14 +17,12 @@ rm $GOPATH/pkg/mod/cache/download/sumdb
|
|||
rm go.sum
|
||||
|
||||
# direct access fails (because localhost.localdev does not exist)
|
||||
# The text of the error message is hard to predict because some DNS servers
|
||||
# will resolve unknown domains like localhost.localdev to a real IP
|
||||
# to serve ads.
|
||||
# web.get is providing the error message - there's no actual network access.
|
||||
cp go.mod.orig go.mod
|
||||
env GOSUMDB=$sumdb
|
||||
env GOPROXY=direct
|
||||
! go get -d rsc.io/fortune@v1.0.0
|
||||
stderr 'verifying.*localhost.localdev'
|
||||
stderr 'verifying module: rsc.io/fortune@v1.0.0: .*: no such host localhost.localdev'
|
||||
rm $GOPATH/pkg/mod/cache/download/sumdb
|
||||
rm go.sum
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func initParserMode() {
|
|||
}
|
||||
}
|
||||
|
||||
func isGoFile(f fs.FileInfo) bool {
|
||||
func isGoFile(f fs.DirEntry) bool {
|
||||
// ignore non-Go files
|
||||
name := f.Name()
|
||||
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
|
||||
|
|
@ -164,7 +164,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
|
|||
return err
|
||||
}
|
||||
|
||||
func visitFile(path string, f fs.FileInfo, err error) error {
|
||||
func visitFile(path string, f fs.DirEntry, err error) error {
|
||||
if err == nil && isGoFile(f) {
|
||||
err = processFile(path, nil, os.Stdout, false)
|
||||
}
|
||||
|
|
@ -177,7 +177,7 @@ func visitFile(path string, f fs.FileInfo, err error) error {
|
|||
}
|
||||
|
||||
func walkDir(path string) {
|
||||
filepath.Walk(path, visitFile)
|
||||
filepath.WalkDir(path, visitFile)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
|||
|
|
@ -108,12 +108,12 @@ func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
|
|||
func genFilenames(t *testing.T, filenames chan<- string) {
|
||||
defer close(filenames)
|
||||
|
||||
handleFile := func(filename string, fi fs.FileInfo, err error) error {
|
||||
handleFile := func(filename string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return nil
|
||||
}
|
||||
if isGoFile(fi) {
|
||||
if isGoFile(d) {
|
||||
filenames <- filename
|
||||
nfiles++
|
||||
}
|
||||
|
|
@ -124,13 +124,13 @@ func genFilenames(t *testing.T, filenames chan<- string) {
|
|||
if *files != "" {
|
||||
for _, filename := range strings.Split(*files, ",") {
|
||||
fi, err := os.Stat(filename)
|
||||
handleFile(filename, fi, err)
|
||||
handleFile(filename, &statDirEntry{fi}, err)
|
||||
}
|
||||
return // ignore files under -root
|
||||
}
|
||||
|
||||
// otherwise, test all Go files under *root
|
||||
filepath.Walk(*root, handleFile)
|
||||
filepath.WalkDir(*root, handleFile)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
|
|
@ -164,3 +164,12 @@ func TestAll(t *testing.T) {
|
|||
fmt.Printf("processed %d files\n", nfiles)
|
||||
}
|
||||
}
|
||||
|
||||
type statDirEntry struct {
|
||||
info fs.FileInfo
|
||||
}
|
||||
|
||||
func (d *statDirEntry) Name() string { return d.info.Name() }
|
||||
func (d *statDirEntry) IsDir() bool { return d.info.IsDir() }
|
||||
func (d *statDirEntry) Type() fs.FileMode { return d.info.Mode().Type() }
|
||||
func (d *statDirEntry) Info() (fs.FileInfo, error) { return d.info, nil }
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -146,3 +147,33 @@ func TestFindAndHash(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExcludedReader(t *testing.T) {
|
||||
const s = "0123456789abcdefghijklmn"
|
||||
tests := []struct {
|
||||
start, end int64 // excluded range
|
||||
results []string // expected results of reads
|
||||
}{
|
||||
{12, 15, []string{"0123456789", "ab\x00\x00\x00fghij", "klmn"}}, // within one read
|
||||
{8, 21, []string{"01234567\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "\x00lmn"}}, // across multiple reads
|
||||
{10, 20, []string{"0123456789", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "klmn"}}, // a whole read
|
||||
{0, 5, []string{"\x00\x00\x00\x00\x0056789", "abcdefghij", "klmn"}}, // start
|
||||
{12, 24, []string{"0123456789", "ab\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00"}}, // end
|
||||
}
|
||||
p := make([]byte, 10)
|
||||
for _, test := range tests {
|
||||
r := &excludedReader{strings.NewReader(s), 0, test.start, test.end}
|
||||
for _, res := range test.results {
|
||||
n, err := r.Read(p)
|
||||
if err != nil {
|
||||
t.Errorf("read failed: %v", err)
|
||||
}
|
||||
if n != len(res) {
|
||||
t.Errorf("unexpected number of bytes read: want %d, got %d", len(res), n)
|
||||
}
|
||||
if string(p[:n]) != res {
|
||||
t.Errorf("unexpected bytes: want %q, got %q", res, p[:n])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ package buildid
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/codesign"
|
||||
"crypto/sha256"
|
||||
"debug/macho"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
|
@ -26,6 +28,11 @@ func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32
|
|||
zeros := make([]byte, len(id))
|
||||
idBytes := []byte(id)
|
||||
|
||||
// For Mach-O files, we want to exclude the code signature.
|
||||
// The code signature contains hashes of the whole file (except the signature
|
||||
// itself), including the buildid. So the buildid cannot contain the signature.
|
||||
r = excludeMachoCodeSignature(r)
|
||||
|
||||
// The strategy is to read the file through buf, looking for id,
|
||||
// but we need to worry about what happens if id is broken up
|
||||
// and returned in parts by two different reads.
|
||||
|
|
@ -87,5 +94,69 @@ func Rewrite(w io.WriterAt, pos []int64, id string) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update Mach-O code signature, if any.
|
||||
if f, cmd, ok := findMachoCodeSignature(w); ok {
|
||||
if codesign.Size(int64(cmd.Dataoff), "a.out") == int64(cmd.Datasize) {
|
||||
// Update the signature if the size matches, so we don't need to
|
||||
// fix up headers. Binaries generated by the Go linker should have
|
||||
// the expected size. Otherwise skip.
|
||||
text := f.Segment("__TEXT")
|
||||
cs := make([]byte, cmd.Datasize)
|
||||
codesign.Sign(cs, w.(io.Reader), "a.out", int64(cmd.Dataoff), int64(text.Offset), int64(text.Filesz), f.Type == macho.TypeExec)
|
||||
if _, err := w.WriteAt(cs, int64(cmd.Dataoff)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func excludeMachoCodeSignature(r io.Reader) io.Reader {
|
||||
_, cmd, ok := findMachoCodeSignature(r)
|
||||
if !ok {
|
||||
return r
|
||||
}
|
||||
return &excludedReader{r, 0, int64(cmd.Dataoff), int64(cmd.Dataoff + cmd.Datasize)}
|
||||
}
|
||||
|
||||
// excludedReader wraps an io.Reader. Reading from it returns the bytes from
|
||||
// the underlying reader, except that when the byte offset is within the
|
||||
// range between start and end, it returns zero bytes.
|
||||
type excludedReader struct {
|
||||
r io.Reader
|
||||
off int64 // current offset
|
||||
start, end int64 // the range to be excluded (read as zero)
|
||||
}
|
||||
|
||||
func (r *excludedReader) Read(p []byte) (int, error) {
|
||||
n, err := r.r.Read(p)
|
||||
if n > 0 && r.off+int64(n) > r.start && r.off < r.end {
|
||||
cstart := r.start - r.off
|
||||
if cstart < 0 {
|
||||
cstart = 0
|
||||
}
|
||||
cend := r.end - r.off
|
||||
if cend > int64(n) {
|
||||
cend = int64(n)
|
||||
}
|
||||
zeros := make([]byte, cend-cstart)
|
||||
copy(p[cstart:cend], zeros)
|
||||
}
|
||||
r.off += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func findMachoCodeSignature(r interface{}) (*macho.File, codesign.CodeSigCmd, bool) {
|
||||
ra, ok := r.(io.ReaderAt)
|
||||
if !ok {
|
||||
return nil, codesign.CodeSigCmd{}, false
|
||||
}
|
||||
f, err := macho.NewFile(ra)
|
||||
if err != nil {
|
||||
return nil, codesign.CodeSigCmd{}, false
|
||||
}
|
||||
cmd, ok := codesign.FindCodeSigCmd(f)
|
||||
return f, cmd, ok
|
||||
}
|
||||
|
|
|
|||
268
src/cmd/internal/codesign/codesign.go
Normal file
268
src/cmd/internal/codesign/codesign.go
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
// Copyright 2020 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 codesign provides basic functionalities for
|
||||
// ad-hoc code signing of Mach-O files.
|
||||
//
|
||||
// This is not a general tool for code-signing. It is made
|
||||
// specifically for the Go toolchain. It uses the same
|
||||
// ad-hoc signing algorithm as the Darwin linker.
|
||||
package codesign
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"debug/macho"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Code signature layout.
|
||||
//
|
||||
// The code signature is a block of bytes that contains
|
||||
// a SuperBlob, which contains one or more Blobs. For ad-hoc
|
||||
// signing, a single CodeDirectory Blob suffices.
|
||||
//
|
||||
// A SuperBlob starts with its header (the binary representation
|
||||
// of the SuperBlob struct), followed by a list of (in our case,
|
||||
// one) Blobs (offset and size). A CodeDirectory Blob starts
|
||||
// with its head (the binary representation of CodeDirectory struct),
|
||||
// followed by the identifier (as a C string) and the hashes, at
|
||||
// the corresponding offsets.
|
||||
//
|
||||
// The signature data must be included in the __LINKEDIT segment.
|
||||
// In the Mach-O file header, an LC_CODE_SIGNATURE load command
|
||||
// points to the data.
|
||||
|
||||
const (
|
||||
pageSizeBits = 12
|
||||
pageSize = 1 << pageSizeBits
|
||||
)
|
||||
|
||||
const LC_CODE_SIGNATURE = 0x1d
|
||||
|
||||
// Constants and struct layouts are from
|
||||
// https://opensource.apple.com/source/xnu/xnu-4903.270.47/osfmk/kern/cs_blobs.h
|
||||
|
||||
const (
|
||||
CSMAGIC_REQUIREMENT = 0xfade0c00 // single Requirement blob
|
||||
CSMAGIC_REQUIREMENTS = 0xfade0c01 // Requirements vector (internal requirements)
|
||||
CSMAGIC_CODEDIRECTORY = 0xfade0c02 // CodeDirectory blob
|
||||
CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 // embedded form of signature data
|
||||
CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1 // multi-arch collection of embedded signatures
|
||||
|
||||
CSSLOT_CODEDIRECTORY = 0 // slot index for CodeDirectory
|
||||
)
|
||||
|
||||
const (
|
||||
CS_HASHTYPE_SHA1 = 1
|
||||
CS_HASHTYPE_SHA256 = 2
|
||||
CS_HASHTYPE_SHA256_TRUNCATED = 3
|
||||
CS_HASHTYPE_SHA384 = 4
|
||||
)
|
||||
|
||||
const (
|
||||
CS_EXECSEG_MAIN_BINARY = 0x1 // executable segment denotes main binary
|
||||
CS_EXECSEG_ALLOW_UNSIGNED = 0x10 // allow unsigned pages (for debugging)
|
||||
CS_EXECSEG_DEBUGGER = 0x20 // main binary is debugger
|
||||
CS_EXECSEG_JIT = 0x40 // JIT enabled
|
||||
CS_EXECSEG_SKIP_LV = 0x80 // skip library validation
|
||||
CS_EXECSEG_CAN_LOAD_CDHASH = 0x100 // can bless cdhash for execution
|
||||
CS_EXECSEG_CAN_EXEC_CDHASH = 0x200 // can execute blessed cdhash
|
||||
)
|
||||
|
||||
type Blob struct {
|
||||
typ uint32 // type of entry
|
||||
offset uint32 // offset of entry
|
||||
// data follows
|
||||
}
|
||||
|
||||
func (b *Blob) put(out []byte) []byte {
|
||||
out = put32be(out, b.typ)
|
||||
out = put32be(out, b.offset)
|
||||
return out
|
||||
}
|
||||
|
||||
const blobSize = 2 * 4
|
||||
|
||||
type SuperBlob struct {
|
||||
magic uint32 // magic number
|
||||
length uint32 // total length of SuperBlob
|
||||
count uint32 // number of index entries following
|
||||
// blobs []Blob
|
||||
}
|
||||
|
||||
func (s *SuperBlob) put(out []byte) []byte {
|
||||
out = put32be(out, s.magic)
|
||||
out = put32be(out, s.length)
|
||||
out = put32be(out, s.count)
|
||||
return out
|
||||
}
|
||||
|
||||
const superBlobSize = 3 * 4
|
||||
|
||||
type CodeDirectory struct {
|
||||
magic uint32 // magic number (CSMAGIC_CODEDIRECTORY)
|
||||
length uint32 // total length of CodeDirectory blob
|
||||
version uint32 // compatibility version
|
||||
flags uint32 // setup and mode flags
|
||||
hashOffset uint32 // offset of hash slot element at index zero
|
||||
identOffset uint32 // offset of identifier string
|
||||
nSpecialSlots uint32 // number of special hash slots
|
||||
nCodeSlots uint32 // number of ordinary (code) hash slots
|
||||
codeLimit uint32 // limit to main image signature range
|
||||
hashSize uint8 // size of each hash in bytes
|
||||
hashType uint8 // type of hash (cdHashType* constants)
|
||||
_pad1 uint8 // unused (must be zero)
|
||||
pageSize uint8 // log2(page size in bytes); 0 => infinite
|
||||
_pad2 uint32 // unused (must be zero)
|
||||
scatterOffset uint32
|
||||
teamOffset uint32
|
||||
_pad3 uint32
|
||||
codeLimit64 uint64
|
||||
execSegBase uint64
|
||||
execSegLimit uint64
|
||||
execSegFlags uint64
|
||||
// data follows
|
||||
}
|
||||
|
||||
func (c *CodeDirectory) put(out []byte) []byte {
|
||||
out = put32be(out, c.magic)
|
||||
out = put32be(out, c.length)
|
||||
out = put32be(out, c.version)
|
||||
out = put32be(out, c.flags)
|
||||
out = put32be(out, c.hashOffset)
|
||||
out = put32be(out, c.identOffset)
|
||||
out = put32be(out, c.nSpecialSlots)
|
||||
out = put32be(out, c.nCodeSlots)
|
||||
out = put32be(out, c.codeLimit)
|
||||
out = put8(out, c.hashSize)
|
||||
out = put8(out, c.hashType)
|
||||
out = put8(out, c._pad1)
|
||||
out = put8(out, c.pageSize)
|
||||
out = put32be(out, c._pad2)
|
||||
out = put32be(out, c.scatterOffset)
|
||||
out = put32be(out, c.teamOffset)
|
||||
out = put32be(out, c._pad3)
|
||||
out = put64be(out, c.codeLimit64)
|
||||
out = put64be(out, c.execSegBase)
|
||||
out = put64be(out, c.execSegLimit)
|
||||
out = put64be(out, c.execSegFlags)
|
||||
return out
|
||||
}
|
||||
|
||||
const codeDirectorySize = 13*4 + 4 + 4*8
|
||||
|
||||
// CodeSigCmd is Mach-O LC_CODE_SIGNATURE load command.
|
||||
type CodeSigCmd struct {
|
||||
Cmd uint32 // LC_CODE_SIGNATURE
|
||||
Cmdsize uint32 // sizeof this command (16)
|
||||
Dataoff uint32 // file offset of data in __LINKEDIT segment
|
||||
Datasize uint32 // file size of data in __LINKEDIT segment
|
||||
}
|
||||
|
||||
func FindCodeSigCmd(f *macho.File) (CodeSigCmd, bool) {
|
||||
get32 := f.ByteOrder.Uint32
|
||||
for _, l := range f.Loads {
|
||||
data := l.Raw()
|
||||
cmd := get32(data)
|
||||
if cmd == LC_CODE_SIGNATURE {
|
||||
return CodeSigCmd{
|
||||
cmd,
|
||||
get32(data[4:]),
|
||||
get32(data[8:]),
|
||||
get32(data[12:]),
|
||||
}, true
|
||||
}
|
||||
}
|
||||
return CodeSigCmd{}, false
|
||||
}
|
||||
|
||||
func put32be(b []byte, x uint32) []byte { binary.BigEndian.PutUint32(b, x); return b[4:] }
|
||||
func put64be(b []byte, x uint64) []byte { binary.BigEndian.PutUint64(b, x); return b[8:] }
|
||||
func put8(b []byte, x uint8) []byte { b[0] = x; return b[1:] }
|
||||
func puts(b, s []byte) []byte { n := copy(b, s); return b[n:] }
|
||||
|
||||
// Size computes the size of the code signature.
|
||||
// id is the identifier used for signing (a field in CodeDirectory blob, which
|
||||
// has no significance in ad-hoc signing).
|
||||
func Size(codeSize int64, id string) int64 {
|
||||
nhashes := (codeSize + pageSize - 1) / pageSize
|
||||
idOff := int64(codeDirectorySize)
|
||||
hashOff := idOff + int64(len(id)+1)
|
||||
cdirSz := hashOff + nhashes*sha256.Size
|
||||
return int64(superBlobSize+blobSize) + cdirSz
|
||||
}
|
||||
|
||||
// Sign generates an ad-hoc code signature and writes it to out.
|
||||
// out must have length at least Size(codeSize, id).
|
||||
// data is the file content without the signature, of size codeSize.
|
||||
// textOff and textSize is the file offset and size of the text segment.
|
||||
// isMain is true if this is a main executable.
|
||||
// id is the identifier used for signing (a field in CodeDirectory blob, which
|
||||
// has no significance in ad-hoc signing).
|
||||
func Sign(out []byte, data io.Reader, id string, codeSize, textOff, textSize int64, isMain bool) {
|
||||
nhashes := (codeSize + pageSize - 1) / pageSize
|
||||
idOff := int64(codeDirectorySize)
|
||||
hashOff := idOff + int64(len(id)+1)
|
||||
sz := Size(codeSize, id)
|
||||
|
||||
// emit blob headers
|
||||
sb := SuperBlob{
|
||||
magic: CSMAGIC_EMBEDDED_SIGNATURE,
|
||||
length: uint32(sz),
|
||||
count: 1,
|
||||
}
|
||||
blob := Blob{
|
||||
typ: CSSLOT_CODEDIRECTORY,
|
||||
offset: superBlobSize + blobSize,
|
||||
}
|
||||
cdir := CodeDirectory{
|
||||
magic: CSMAGIC_CODEDIRECTORY,
|
||||
length: uint32(sz) - (superBlobSize + blobSize),
|
||||
version: 0x20400,
|
||||
flags: 0x20002, // adhoc | linkerSigned
|
||||
hashOffset: uint32(hashOff),
|
||||
identOffset: uint32(idOff),
|
||||
nCodeSlots: uint32(nhashes),
|
||||
codeLimit: uint32(codeSize),
|
||||
hashSize: sha256.Size,
|
||||
hashType: CS_HASHTYPE_SHA256,
|
||||
pageSize: uint8(pageSizeBits),
|
||||
execSegBase: uint64(textOff),
|
||||
execSegLimit: uint64(textSize),
|
||||
}
|
||||
if isMain {
|
||||
cdir.execSegFlags = CS_EXECSEG_MAIN_BINARY
|
||||
}
|
||||
|
||||
outp := out
|
||||
outp = sb.put(outp)
|
||||
outp = blob.put(outp)
|
||||
outp = cdir.put(outp)
|
||||
|
||||
// emit the identifier
|
||||
outp = puts(outp, []byte(id+"\000"))
|
||||
|
||||
// emit hashes
|
||||
var buf [pageSize]byte
|
||||
h := sha256.New()
|
||||
p := 0
|
||||
for p < int(codeSize) {
|
||||
n, err := io.ReadFull(data, buf[:])
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
panic(err)
|
||||
}
|
||||
if p+n > int(codeSize) {
|
||||
n = int(codeSize) - p
|
||||
}
|
||||
p += n
|
||||
h.Reset()
|
||||
h.Write(buf[:n])
|
||||
b := h.Sum(nil)
|
||||
outp = puts(outp, b[:])
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ func findGorootModules(t *testing.T) []gorootModule {
|
|||
goBin := testenv.GoToolPath(t)
|
||||
|
||||
goroot.once.Do(func() {
|
||||
goroot.err = filepath.Walk(runtime.GOROOT(), func(path string, info fs.FileInfo, err error) error {
|
||||
goroot.err = filepath.WalkDir(runtime.GOROOT(), func(path string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1777,15 +1777,15 @@ func instructionsForProg(p *obj.Prog) []*instruction {
|
|||
case ABGEZ:
|
||||
ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
|
||||
case ABGT:
|
||||
ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.Reg), uint32(p.From.Reg)
|
||||
ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
|
||||
case ABGTU:
|
||||
ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.Reg)
|
||||
ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
|
||||
case ABGTZ:
|
||||
ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
|
||||
case ABLE:
|
||||
ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.Reg), uint32(p.From.Reg)
|
||||
ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
|
||||
case ABLEU:
|
||||
ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg)
|
||||
ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
|
||||
case ABLEZ:
|
||||
ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
|
||||
case ABLTZ:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import (
|
|||
)
|
||||
|
||||
func testBEQZ(a int64) (r bool)
|
||||
func testBGE(a, b int64) (r bool)
|
||||
func testBGEU(a, b int64) (r bool)
|
||||
func testBGEZ(a int64) (r bool)
|
||||
func testBGT(a, b int64) (r bool)
|
||||
func testBGTU(a, b int64) (r bool)
|
||||
|
|
@ -18,6 +20,8 @@ func testBGTZ(a int64) (r bool)
|
|||
func testBLE(a, b int64) (r bool)
|
||||
func testBLEU(a, b int64) (r bool)
|
||||
func testBLEZ(a int64) (r bool)
|
||||
func testBLT(a, b int64) (r bool)
|
||||
func testBLTU(a, b int64) (r bool)
|
||||
func testBLTZ(a int64) (r bool)
|
||||
func testBNEZ(a int64) (r bool)
|
||||
|
||||
|
|
@ -29,30 +33,75 @@ func TestBranchCondition(t *testing.T) {
|
|||
fn func(a, b int64) bool
|
||||
want bool
|
||||
}{
|
||||
{"BGT", 0, 1, testBGT, true},
|
||||
{"BGE", 0, 1, testBGE, false},
|
||||
{"BGE", 0, 0, testBGE, true},
|
||||
{"BGE", 0, -1, testBGE, true},
|
||||
{"BGE", -1, 0, testBGE, false},
|
||||
{"BGE", 1, 0, testBGE, true},
|
||||
{"BGEU", 0, 1, testBGEU, false},
|
||||
{"BGEU", 0, 0, testBGEU, true},
|
||||
{"BGEU", 0, -1, testBGEU, false},
|
||||
{"BGEU", -1, 0, testBGEU, true},
|
||||
{"BGEU", 1, 0, testBGEU, true},
|
||||
{"BGT", 0, 1, testBGT, false},
|
||||
{"BGT", 0, 0, testBGT, false},
|
||||
{"BGT", 0, -1, testBGT, false},
|
||||
{"BGT", -1, 0, testBGT, true},
|
||||
{"BGT", 1, 0, testBGT, false},
|
||||
{"BGTU", 0, 1, testBGTU, true},
|
||||
{"BGTU", 0, -1, testBGTU, true},
|
||||
{"BGTU", -1, 0, testBGTU, false},
|
||||
{"BGTU", 1, 0, testBGTU, false},
|
||||
{"BLE", 0, 1, testBLE, false},
|
||||
{"BLE", 0, -1, testBLE, true},
|
||||
{"BGT", 0, -1, testBGT, true},
|
||||
{"BGT", -1, 0, testBGT, false},
|
||||
{"BGT", 1, 0, testBGT, true},
|
||||
{"BGTU", 0, 1, testBGTU, false},
|
||||
{"BGTU", 0, 0, testBGTU, false},
|
||||
{"BGTU", 0, -1, testBGTU, false},
|
||||
{"BGTU", -1, 0, testBGTU, true},
|
||||
{"BGTU", 1, 0, testBGTU, true},
|
||||
{"BLE", 0, 1, testBLE, true},
|
||||
{"BLE", 0, 0, testBLE, true},
|
||||
{"BLE", -1, 0, testBLE, false},
|
||||
{"BLE", 1, 0, testBLE, true},
|
||||
{"BLEU", 0, 1, testBLEU, false},
|
||||
{"BLEU", 0, -1, testBLEU, false},
|
||||
{"BLE", 0, -1, testBLE, false},
|
||||
{"BLE", -1, 0, testBLE, true},
|
||||
{"BLE", 1, 0, testBLE, false},
|
||||
{"BLEU", 0, 1, testBLEU, true},
|
||||
{"BLEU", 0, 0, testBLEU, true},
|
||||
{"BLEU", -1, 0, testBLEU, true},
|
||||
{"BLEU", 1, 0, testBLEU, true},
|
||||
{"BLEU", 0, -1, testBLEU, true},
|
||||
{"BLEU", -1, 0, testBLEU, false},
|
||||
{"BLEU", 1, 0, testBLEU, false},
|
||||
{"BLT", 0, 1, testBLT, true},
|
||||
{"BLT", 0, 0, testBLT, false},
|
||||
{"BLT", 0, -1, testBLT, false},
|
||||
{"BLT", -1, 0, testBLT, true},
|
||||
{"BLT", 1, 0, testBLT, false},
|
||||
{"BLTU", 0, 1, testBLTU, true},
|
||||
{"BLTU", 0, 0, testBLTU, false},
|
||||
{"BLTU", 0, -1, testBLTU, true},
|
||||
{"BLTU", -1, 0, testBLTU, false},
|
||||
{"BLTU", 1, 0, testBLTU, false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.ins, func(t *testing.T) {
|
||||
var fn func(a, b int64) bool
|
||||
switch test.ins {
|
||||
case "BGE":
|
||||
fn = func(a, b int64) bool { return a >= b }
|
||||
case "BGEU":
|
||||
fn = func(a, b int64) bool { return uint64(a) >= uint64(b) }
|
||||
case "BGT":
|
||||
fn = func(a, b int64) bool { return a > b }
|
||||
case "BGTU":
|
||||
fn = func(a, b int64) bool { return uint64(a) > uint64(b) }
|
||||
case "BLE":
|
||||
fn = func(a, b int64) bool { return a <= b }
|
||||
case "BLEU":
|
||||
fn = func(a, b int64) bool { return uint64(a) <= uint64(b) }
|
||||
case "BLT":
|
||||
fn = func(a, b int64) bool { return a < b }
|
||||
case "BLTU":
|
||||
fn = func(a, b int64) bool { return uint64(a) < uint64(b) }
|
||||
default:
|
||||
t.Fatalf("Unknown instruction %q", test.ins)
|
||||
}
|
||||
if got := fn(test.a, test.b); got != test.want {
|
||||
t.Errorf("Go %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
|
||||
}
|
||||
if got := test.fn(test.a, test.b); got != test.want {
|
||||
t.Errorf("%v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
|
||||
t.Errorf("Assembly %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,28 @@ b:
|
|||
MOV X6, r+8(FP)
|
||||
RET
|
||||
|
||||
// func testBGE(a, b int64) (r bool)
|
||||
TEXT ·testBGE(SB),NOSPLIT,$0-0
|
||||
MOV a+0(FP), X5
|
||||
MOV b+8(FP), X6
|
||||
MOV $1, X7
|
||||
BGE X5, X6, b
|
||||
MOV $0, X7
|
||||
b:
|
||||
MOV X7, r+16(FP)
|
||||
RET
|
||||
|
||||
// func testBGEU(a, b int64) (r bool)
|
||||
TEXT ·testBGEU(SB),NOSPLIT,$0-0
|
||||
MOV a+0(FP), X5
|
||||
MOV b+8(FP), X6
|
||||
MOV $1, X7
|
||||
BGEU X5, X6, b
|
||||
MOV $0, X7
|
||||
b:
|
||||
MOV X7, r+16(FP)
|
||||
RET
|
||||
|
||||
// func testBGEZ(a int64) (r bool)
|
||||
TEXT ·testBGEZ(SB),NOSPLIT,$0-0
|
||||
MOV a+0(FP), X5
|
||||
|
|
@ -90,6 +112,28 @@ b:
|
|||
MOV X6, r+8(FP)
|
||||
RET
|
||||
|
||||
// func testBLT(a, b int64) (r bool)
|
||||
TEXT ·testBLT(SB),NOSPLIT,$0-0
|
||||
MOV a+0(FP), X5
|
||||
MOV b+8(FP), X6
|
||||
MOV $1, X7
|
||||
BLT X5, X6, b
|
||||
MOV $0, X7
|
||||
b:
|
||||
MOV X7, r+16(FP)
|
||||
RET
|
||||
|
||||
// func testBLTU(a, b int64) (r bool)
|
||||
TEXT ·testBLTU(SB),NOSPLIT,$0-0
|
||||
MOV a+0(FP), X5
|
||||
MOV b+8(FP), X6
|
||||
MOV $1, X7
|
||||
BLTU X5, X6, b
|
||||
MOV $0, X7
|
||||
b:
|
||||
MOV X7, r+16(FP)
|
||||
RET
|
||||
|
||||
// func testBLTZ(a int64) (r bool)
|
||||
TEXT ·testBLTZ(SB),NOSPLIT,$0-0
|
||||
MOV a+0(FP), X5
|
||||
|
|
|
|||
|
|
@ -413,11 +413,7 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
|
|||
case objabi.R_CALL:
|
||||
if siz == 4 {
|
||||
if ldr.SymType(r.Xsym) == sym.SDYNIMPORT {
|
||||
if ctxt.DynlinkingGo() {
|
||||
out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
|
||||
}
|
||||
out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
|
||||
} else {
|
||||
out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,11 +35,12 @@ func (mode *BuildMode) Set(s string) error {
|
|||
default:
|
||||
return fmt.Errorf("invalid buildmode: %q", s)
|
||||
case "exe":
|
||||
if objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" {
|
||||
*mode = BuildModePIE // On darwin/arm64 everything is PIE.
|
||||
break
|
||||
switch objabi.GOOS + "/" + objabi.GOARCH {
|
||||
case "darwin/arm64", "windows/arm": // On these platforms, everything is PIE
|
||||
*mode = BuildModePIE
|
||||
default:
|
||||
*mode = BuildModeExe
|
||||
}
|
||||
*mode = BuildModeExe
|
||||
case "pie":
|
||||
switch objabi.GOOS {
|
||||
case "aix", "android", "linux", "windows", "darwin", "ios":
|
||||
|
|
|
|||
|
|
@ -298,6 +298,11 @@ func (ctxt *Link) CanUsePlugins() bool {
|
|||
return ctxt.canUsePlugins
|
||||
}
|
||||
|
||||
// NeedCodeSign reports whether we need to code-sign the output binary.
|
||||
func (ctxt *Link) NeedCodeSign() bool {
|
||||
return ctxt.IsDarwin() && ctxt.IsARM64()
|
||||
}
|
||||
|
||||
var (
|
||||
dynlib []string
|
||||
ldflag []string
|
||||
|
|
@ -1642,6 +1647,12 @@ func (ctxt *Link) hostlink() {
|
|||
Exitf("%s: %v", os.Args[0], err)
|
||||
}
|
||||
}
|
||||
if ctxt.NeedCodeSign() {
|
||||
err := machoCodeSign(ctxt, *flagOutfile)
|
||||
if err != nil {
|
||||
Exitf("%s: code signing failed: %v", os.Args[0], err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var createTrivialCOnce sync.Once
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package ld
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/codesign"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
|
|
@ -17,6 +18,7 @@ import (
|
|||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type MachoHdr struct {
|
||||
|
|
@ -245,6 +247,8 @@ const (
|
|||
BIND_SUBOPCODE_THREADED_APPLY = 0x01
|
||||
)
|
||||
|
||||
const machoHeaderSize64 = 8 * 4 // size of 64-bit Mach-O header
|
||||
|
||||
// Mach-O file writing
|
||||
// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
|
||||
|
||||
|
|
@ -643,6 +647,8 @@ func asmbMacho(ctxt *Link) {
|
|||
}
|
||||
ctxt.Out.SeekSet(0)
|
||||
|
||||
ldr := ctxt.loader
|
||||
|
||||
/* apple MACH */
|
||||
va := *FlagTextAddr - int64(HEADR)
|
||||
|
||||
|
|
@ -757,25 +763,27 @@ func asmbMacho(ctxt *Link) {
|
|||
}
|
||||
}
|
||||
|
||||
var codesigOff int64
|
||||
if !*FlagD {
|
||||
ldr := ctxt.loader
|
||||
|
||||
// must match domacholink below
|
||||
// must match doMachoLink below
|
||||
s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
|
||||
s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
|
||||
s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
|
||||
s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
|
||||
s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
|
||||
s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
|
||||
s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
|
||||
|
||||
if ctxt.LinkMode != LinkExternal {
|
||||
ms := newMachoSeg("__LINKEDIT", 0)
|
||||
ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound)))
|
||||
ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6)
|
||||
ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7)
|
||||
ms.fileoffset = uint64(linkoff)
|
||||
ms.filesize = ms.vsize
|
||||
ms.prot1 = 1
|
||||
ms.prot2 = 1
|
||||
|
||||
codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6
|
||||
}
|
||||
|
||||
if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
|
||||
|
|
@ -814,12 +822,31 @@ func asmbMacho(ctxt *Link) {
|
|||
stringtouint32(ml.data[4:], lib)
|
||||
}
|
||||
}
|
||||
|
||||
if ctxt.IsInternal() && ctxt.NeedCodeSign() {
|
||||
ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
|
||||
ml.data[0] = uint32(codesigOff)
|
||||
ml.data[1] = uint32(s7)
|
||||
}
|
||||
}
|
||||
|
||||
a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
|
||||
if int32(a) > HEADR {
|
||||
Exitf("HEADR too small: %d > %d", a, HEADR)
|
||||
}
|
||||
|
||||
// Now we have written everything. Compute the code signature (which
|
||||
// is a hash of the file content, so it must be done at last.)
|
||||
if ctxt.IsInternal() && ctxt.NeedCodeSign() {
|
||||
cs := ldr.Lookup(".machocodesig", 0)
|
||||
data := ctxt.Out.Data()
|
||||
if int64(len(data)) != codesigOff {
|
||||
panic("wrong size")
|
||||
}
|
||||
codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(Segtext.Fileoff), int64(Segtext.Filelen), ctxt.IsExe() || ctxt.IsPIE())
|
||||
ctxt.Out.SeekSet(codesigOff)
|
||||
ctxt.Out.Write(ldr.Data(cs))
|
||||
}
|
||||
}
|
||||
|
||||
func symkind(ldr *loader.Loader, s loader.Sym) int {
|
||||
|
|
@ -1057,7 +1084,6 @@ func machodysymtab(ctxt *Link, base int64) {
|
|||
|
||||
func doMachoLink(ctxt *Link) int64 {
|
||||
machosymtab(ctxt)
|
||||
|
||||
machoDyldInfo(ctxt)
|
||||
|
||||
ldr := ctxt.loader
|
||||
|
|
@ -1070,6 +1096,8 @@ func doMachoLink(ctxt *Link) int64 {
|
|||
s5 := ctxt.ArchSyms.LinkEditGOT
|
||||
s6 := ldr.Lookup(".machosymstr", 0)
|
||||
|
||||
size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
|
||||
|
||||
// Force the linkedit section to end on a 16-byte
|
||||
// boundary. This allows pure (non-cgo) Go binaries
|
||||
// to be code signed correctly.
|
||||
|
|
@ -1087,13 +1115,14 @@ func doMachoLink(ctxt *Link) int64 {
|
|||
// boundary, codesign_allocate will not need to apply
|
||||
// any alignment padding itself, working around the
|
||||
// issue.
|
||||
s6b := ldr.MakeSymbolUpdater(s6)
|
||||
for s6b.Size()%16 != 0 {
|
||||
s6b.AddUint8(0)
|
||||
if size%16 != 0 {
|
||||
n := 16 - size%16
|
||||
s6b := ldr.MakeSymbolUpdater(s6)
|
||||
s6b.Grow(s6b.Size() + n)
|
||||
s6b.SetSize(s6b.Size() + n)
|
||||
size += n
|
||||
}
|
||||
|
||||
size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6))
|
||||
|
||||
if size > 0 {
|
||||
linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
|
||||
ctxt.Out.SeekSet(linkoff)
|
||||
|
|
@ -1104,9 +1133,13 @@ func doMachoLink(ctxt *Link) int64 {
|
|||
ctxt.Out.Write(ldr.Data(s4))
|
||||
ctxt.Out.Write(ldr.Data(s5))
|
||||
ctxt.Out.Write(ldr.Data(s6))
|
||||
|
||||
// Add code signature if necessary. This must be the last.
|
||||
s7 := machoCodeSigSym(ctxt, linkoff+size)
|
||||
size += ldr.SymSize(s7)
|
||||
}
|
||||
|
||||
return Rnd(int64(size), int64(*FlagRound))
|
||||
return Rnd(size, int64(*FlagRound))
|
||||
}
|
||||
|
||||
func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
|
||||
|
|
@ -1378,3 +1411,94 @@ func machoDyldInfo(ctxt *Link) {
|
|||
// e.g. dlsym'd. But internal linking is not the default in that case, so
|
||||
// it is fine.
|
||||
}
|
||||
|
||||
// machoCodeSigSym creates and returns a symbol for code signature.
|
||||
// The symbol context is left as zeros, which will be generated at the end
|
||||
// (as it depends on the rest of the file).
|
||||
func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
|
||||
ldr := ctxt.loader
|
||||
cs := ldr.CreateSymForUpdate(".machocodesig", 0)
|
||||
if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
|
||||
return cs.Sym()
|
||||
}
|
||||
sz := codesign.Size(codeSize, "a.out")
|
||||
cs.Grow(sz)
|
||||
cs.SetSize(sz)
|
||||
return cs.Sym()
|
||||
}
|
||||
|
||||
// machoCodeSign code-signs Mach-O file fname with an ad-hoc signature.
|
||||
// This is used for updating an external linker generated binary.
|
||||
func machoCodeSign(ctxt *Link, fname string) error {
|
||||
f, err := os.OpenFile(fname, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
mf, err := macho.NewFile(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if mf.Magic != macho.Magic64 {
|
||||
Exitf("not 64-bit Mach-O file: %s", fname)
|
||||
}
|
||||
|
||||
// Find existing LC_CODE_SIGNATURE and __LINKEDIT segment
|
||||
var sigOff, sigSz, csCmdOff, linkeditOff int64
|
||||
var linkeditSeg, textSeg *macho.Segment
|
||||
loadOff := int64(machoHeaderSize64)
|
||||
get32 := mf.ByteOrder.Uint32
|
||||
for _, l := range mf.Loads {
|
||||
data := l.Raw()
|
||||
cmd, sz := get32(data), get32(data[4:])
|
||||
if cmd == LC_CODE_SIGNATURE {
|
||||
sigOff = int64(get32(data[8:]))
|
||||
sigSz = int64(get32(data[12:]))
|
||||
csCmdOff = loadOff
|
||||
}
|
||||
if seg, ok := l.(*macho.Segment); ok {
|
||||
switch seg.Name {
|
||||
case "__LINKEDIT":
|
||||
linkeditSeg = seg
|
||||
linkeditOff = loadOff
|
||||
case "__TEXT":
|
||||
textSeg = seg
|
||||
}
|
||||
}
|
||||
loadOff += int64(sz)
|
||||
}
|
||||
|
||||
if sigOff == 0 {
|
||||
// The C linker doesn't generate a signed binary, for some reason.
|
||||
// Skip.
|
||||
return nil
|
||||
}
|
||||
sz := codesign.Size(sigOff, "a.out")
|
||||
if sz != sigSz {
|
||||
// Update the load command,
|
||||
var tmp [8]byte
|
||||
mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
|
||||
_, err = f.WriteAt(tmp[:4], csCmdOff+12)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Uodate the __LINKEDIT segment.
|
||||
segSz := sigOff + sz - int64(linkeditSeg.Offset)
|
||||
mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
|
||||
_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cs := make([]byte, sz)
|
||||
codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
|
||||
_, err = f.WriteAt(cs, sigOff)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ func (out *OutBuf) Close() error {
|
|||
}
|
||||
if out.isMmapped() {
|
||||
out.copyHeap()
|
||||
out.purgeSignatureCache()
|
||||
out.munmap()
|
||||
}
|
||||
if out.f == nil {
|
||||
|
|
@ -135,6 +136,15 @@ func (out *OutBuf) isMmapped() bool {
|
|||
return len(out.buf) != 0
|
||||
}
|
||||
|
||||
// Data returns the whole written OutBuf as a byte slice.
|
||||
func (out *OutBuf) Data() []byte {
|
||||
if out.isMmapped() {
|
||||
out.copyHeap()
|
||||
return out.buf
|
||||
}
|
||||
return out.heap
|
||||
}
|
||||
|
||||
// copyHeap copies the heap to the mmapped section of memory, returning true if
|
||||
// a copy takes place.
|
||||
func (out *OutBuf) copyHeap() bool {
|
||||
|
|
|
|||
|
|
@ -36,3 +36,12 @@ func (out *OutBuf) fallocate(size uint64) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (out *OutBuf) purgeSignatureCache() {
|
||||
// Apparently, the Darwin kernel may cache the code signature at mmap.
|
||||
// When we mmap the output buffer, it doesn't have a code signature
|
||||
// (as we haven't generated one). Invalidate the kernel cache now that
|
||||
// we have generated the signature. See issue #42684.
|
||||
syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&out.buf[0])), uintptr(len(out.buf)), syscall.MS_INVALIDATE)
|
||||
// Best effort. Ignore error.
|
||||
}
|
||||
|
|
|
|||
9
src/cmd/link/internal/ld/outbuf_notdarwin.go
Normal file
9
src/cmd/link/internal/ld/outbuf_notdarwin.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2020 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.
|
||||
|
||||
// +build !darwin
|
||||
|
||||
package ld
|
||||
|
||||
func (out *OutBuf) purgeSignatureCache() {}
|
||||
3
src/cmd/vendor/golang.org/x/mod/semver/semver.go
generated
vendored
3
src/cmd/vendor/golang.org/x/mod/semver/semver.go
generated
vendored
|
|
@ -138,6 +138,9 @@ func Compare(v, w string) int {
|
|||
|
||||
// Max canonicalizes its arguments and then returns the version string
|
||||
// that compares greater.
|
||||
//
|
||||
// Deprecated: use Compare instead. In most cases, returning a canonicalized
|
||||
// version is not expected or desired.
|
||||
func Max(v, w string) string {
|
||||
v = Canonical(v)
|
||||
w = Canonical(w)
|
||||
|
|
|
|||
2
src/cmd/vendor/modules.txt
vendored
2
src/cmd/vendor/modules.txt
vendored
|
|
@ -29,7 +29,7 @@ golang.org/x/arch/x86/x86asm
|
|||
golang.org/x/crypto/ed25519
|
||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||
golang.org/x/crypto/ssh/terminal
|
||||
# golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
|
||||
# golang.org/x/mod v0.4.0
|
||||
## explicit
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/modfile
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func TestGZIPFilesHaveZeroMTimes(t *testing.T) {
|
|||
t.Fatal("error evaluating GOROOT: ", err)
|
||||
}
|
||||
var files []string
|
||||
err = filepath.Walk(goroot, func(path string, info fs.FileInfo, err error) error {
|
||||
err = filepath.WalkDir(goroot, func(path string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ func (p *ExtendedGroupElement) FromBytes(s *[32]byte) bool {
|
|||
FeOne(&p.Z)
|
||||
FeSquare(&u, &p.Y)
|
||||
FeMul(&v, &u, &d)
|
||||
FeSub(&u, &u, &p.Z) // y = y^2-1
|
||||
FeSub(&u, &u, &p.Z) // u = y^2-1
|
||||
FeAdd(&v, &v, &p.Z) // v = dy^2+1
|
||||
|
||||
FeSquare(&v3, &v)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ type SyntaxError struct {
|
|||
Offset int64 // error occurred after reading Offset bytes
|
||||
}
|
||||
|
||||
func (e *SyntaxError) Error() string { return "json: " + e.msg }
|
||||
func (e *SyntaxError) Error() string { return e.msg }
|
||||
|
||||
// A scanner is a JSON scanning state machine.
|
||||
// Callers call scan.reset and then pass bytes in one at a time
|
||||
|
|
|
|||
|
|
@ -510,8 +510,8 @@ func listStdPkgs(goroot string) ([]string, error) {
|
|||
var pkgs []string
|
||||
|
||||
src := filepath.Join(goroot, "src") + string(filepath.Separator)
|
||||
walkFn := func(path string, fi fs.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() || path == src {
|
||||
walkFn := func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil || !d.IsDir() || path == src {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -528,7 +528,7 @@ func listStdPkgs(goroot string) ([]string, error) {
|
|||
pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
|
||||
return nil
|
||||
}
|
||||
if err := filepath.Walk(src, walkFn); err != nil {
|
||||
if err := filepath.WalkDir(src, walkFn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pkgs, nil
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ func main() {
|
|||
flag.Parse()
|
||||
fset := token.NewFileSet()
|
||||
nheadings := 0
|
||||
err := filepath.Walk(*root, func(path string, fi fs.FileInfo, err error) error {
|
||||
if !fi.IsDir() {
|
||||
err := filepath.WalkDir(*root, func(path string, info fs.DirEntry, err error) error {
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments)
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ func ParseDir(fset *token.FileSet, path string, filter func(fs.FileInfo) bool, m
|
|||
|
||||
pkgs = make(map[string]*ast.Package)
|
||||
for _, d := range list {
|
||||
if strings.HasSuffix(d.Name(), ".go") && (filter == nil || filter(d)) {
|
||||
if !d.IsDir() && strings.HasSuffix(d.Name(), ".go") && (filter == nil || filter(d)) {
|
||||
filename := filepath.Join(path, d.Name())
|
||||
if src, err := ParseFile(fset, filename, nil, mode); err == nil {
|
||||
name := src.Name.Name
|
||||
|
|
|
|||
|
|
@ -82,6 +82,14 @@ func TestParseDir(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIssue42951(t *testing.T) {
|
||||
path := "./testdata/issue42951"
|
||||
_, err := ParseDir(token.NewFileSet(), path, nil, 0)
|
||||
if err != nil {
|
||||
t.Errorf("ParseDir(%s): %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseExpr(t *testing.T) {
|
||||
// just kicking the tires:
|
||||
// a valid arithmetic expression
|
||||
|
|
|
|||
1
src/go/parser/testdata/issue42951/not_a_file.go/invalid.go
vendored
Normal file
1
src/go/parser/testdata/issue42951/not_a_file.go/invalid.go
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
This file should not be parsed by ParseDir.
|
||||
|
|
@ -243,7 +243,7 @@ func TestEscape(t *testing.T) {
|
|||
{
|
||||
"badMarshaler",
|
||||
`<button onclick='alert(1/{{.B}}in numbers)'>`,
|
||||
`<button onclick='alert(1/ /* json: error calling MarshalJSON for type *template.badMarshaler: json: invalid character 'f' looking for beginning of object key string */null in numbers)'>`,
|
||||
`<button onclick='alert(1/ /* json: error calling MarshalJSON for type *template.badMarshaler: invalid character 'f' looking for beginning of object key string */null in numbers)'>`,
|
||||
},
|
||||
{
|
||||
"jsMarshaler",
|
||||
|
|
|
|||
|
|
@ -503,7 +503,7 @@ func makeText(name string) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
case "go":
|
||||
err := filepath.Walk("../..", func(path string, info fs.FileInfo, err error) error {
|
||||
err := filepath.WalkDir("../..", func(path string, info fs.DirEntry, err error) error {
|
||||
if err == nil && strings.HasSuffix(path, ".go") && !info.IsDir() {
|
||||
file, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ioutil implements some I/O utility functions.
|
||||
//
|
||||
// As of Go 1.16, the same functionality is now provided
|
||||
// by package io or package os, and those implementations
|
||||
// should be preferred in new code.
|
||||
// See the specific function documentation for details.
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
|
|
@ -26,67 +31,30 @@ func ReadAll(r io.Reader) ([]byte, error) {
|
|||
// A successful call returns err == nil, not err == EOF. Because ReadFile
|
||||
// reads the whole file, it does not treat an EOF from Read as an error
|
||||
// to be reported.
|
||||
//
|
||||
// As of Go 1.16, this function simply calls os.ReadFile.
|
||||
func ReadFile(filename string) ([]byte, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
// It's a good but not certain bet that FileInfo will tell us exactly how much to
|
||||
// read, so let's try it but be prepared for the answer to be wrong.
|
||||
const minRead = 512
|
||||
var n int64 = minRead
|
||||
|
||||
if fi, err := f.Stat(); err == nil {
|
||||
// As initial capacity for readAll, use Size + a little extra in case Size
|
||||
// is zero, and to avoid another allocation after Read has filled the
|
||||
// buffer. The readAll call will read into its allocated internal buffer
|
||||
// cheaply. If the size was wrong, we'll either waste some space off the end
|
||||
// or reallocate as needed, but in the overwhelmingly common case we'll get
|
||||
// it just right.
|
||||
if size := fi.Size() + minRead; size > n {
|
||||
n = size
|
||||
}
|
||||
}
|
||||
|
||||
if int64(int(n)) != n {
|
||||
n = minRead
|
||||
}
|
||||
|
||||
b := make([]byte, 0, n)
|
||||
for {
|
||||
if len(b) == cap(b) {
|
||||
// Add more capacity (let append pick how much).
|
||||
b = append(b, 0)[:len(b)]
|
||||
}
|
||||
n, err := f.Read(b[len(b):cap(b)])
|
||||
b = b[:len(b)+n]
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return b, err
|
||||
}
|
||||
}
|
||||
return os.ReadFile(filename)
|
||||
}
|
||||
|
||||
// WriteFile writes data to a file named by filename.
|
||||
// If the file does not exist, WriteFile creates it with permissions perm
|
||||
// (before umask); otherwise WriteFile truncates it before writing, without changing permissions.
|
||||
//
|
||||
// As of Go 1.16, this function simply calls os.WriteFile.
|
||||
func WriteFile(filename string, data []byte, perm fs.FileMode) error {
|
||||
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(data)
|
||||
if err1 := f.Close(); err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
return os.WriteFile(filename, data, perm)
|
||||
}
|
||||
|
||||
// ReadDir reads the directory named by dirname and returns
|
||||
// a list of directory entries sorted by filename.
|
||||
// a list of fs.FileInfo for the directory's contents,
|
||||
// sorted by filename. If an error occurs reading the directory,
|
||||
// ReadDir returns no directory entries along with the error.
|
||||
//
|
||||
// As of Go 1.16, os.ReadDir is a more efficient and correct choice:
|
||||
// it returns a list of fs.DirEntry instead of fs.FileInfo,
|
||||
// and it returns partial results in the case of an error
|
||||
// midway through reading a directory.
|
||||
func ReadDir(dirname string) ([]fs.FileInfo, error) {
|
||||
f, err := os.Open(dirname)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ func (l *Logger) SetOutput(w io.Writer) {
|
|||
|
||||
var std = New(os.Stderr, "", LstdFlags)
|
||||
|
||||
// Default returns the *Logger used by the package-level output functions.
|
||||
// Default returns the standard logger used by the package-level output functions.
|
||||
func Default() *Logger { return std }
|
||||
|
||||
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
|
||||
|
|
|
|||
|
|
@ -352,10 +352,16 @@ func (r *Response) bodyIsWritable() bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
// isProtocolSwitch reports whether r is a response to a successful
|
||||
// protocol upgrade.
|
||||
// isProtocolSwitch reports whether the response code and header
|
||||
// indicate a successful protocol upgrade response.
|
||||
func (r *Response) isProtocolSwitch() bool {
|
||||
return r.StatusCode == StatusSwitchingProtocols &&
|
||||
r.Header.Get("Upgrade") != "" &&
|
||||
httpguts.HeaderValuesContainsToken(r.Header["Connection"], "Upgrade")
|
||||
return isProtocolSwitchResponse(r.StatusCode, r.Header)
|
||||
}
|
||||
|
||||
// isProtocolSwitchResponse reports whether the response code and
|
||||
// response header indicate a successful protocol upgrade response.
|
||||
func isProtocolSwitchResponse(code int, h Header) bool {
|
||||
return code == StatusSwitchingProtocols &&
|
||||
h.Get("Upgrade") != "" &&
|
||||
httpguts.HeaderValuesContainsToken(h["Connection"], "Upgrade")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6448,3 +6448,56 @@ func BenchmarkResponseStatusLine(b *testing.B) {
|
|||
}
|
||||
})
|
||||
}
|
||||
func TestDisableKeepAliveUpgrade(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
|
||||
setParallel(t)
|
||||
defer afterTest(t)
|
||||
|
||||
s := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
w.Header().Set("Connection", "Upgrade")
|
||||
w.Header().Set("Upgrade", "someProto")
|
||||
w.WriteHeader(StatusSwitchingProtocols)
|
||||
c, _, err := w.(Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
io.Copy(c, c)
|
||||
}))
|
||||
s.Config.SetKeepAlivesEnabled(false)
|
||||
s.Start()
|
||||
defer s.Close()
|
||||
|
||||
cl := s.Client()
|
||||
cl.Transport.(*Transport).DisableKeepAlives = true
|
||||
|
||||
resp, err := cl.Get(s.URL)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to perform request: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
rwc, ok := resp.Body.(io.ReadWriteCloser)
|
||||
if !ok {
|
||||
t.Fatalf("Response.Body is not a io.ReadWriteCloser: %T", resp.Body)
|
||||
}
|
||||
|
||||
_, err = rwc.Write([]byte("hello"))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to write to body: %v", err)
|
||||
}
|
||||
|
||||
b := make([]byte, 5)
|
||||
_, err = io.ReadFull(rwc, b)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read from body: %v", err)
|
||||
}
|
||||
|
||||
if string(b) != "hello" {
|
||||
t.Fatalf("unexpected value read from body:\ngot: %q\nwant: %q", b, "hello")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1468,7 +1468,13 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
|||
return
|
||||
}
|
||||
|
||||
if w.closeAfterReply && (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) {
|
||||
// Only override the Connection header if it is not a successful
|
||||
// protocol switch response and if KeepAlives are not enabled.
|
||||
// See https://golang.org/issue/36381.
|
||||
delConnectionHeader := w.closeAfterReply &&
|
||||
(!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) &&
|
||||
!isProtocolSwitchResponse(w.status, header)
|
||||
if delConnectionHeader {
|
||||
delHeader("Connection")
|
||||
if w.req.ProtoAtLeast(1, 1) {
|
||||
setHeader.connection = "close"
|
||||
|
|
|
|||
|
|
@ -2599,6 +2599,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
|
|||
var respHeaderTimer <-chan time.Time
|
||||
cancelChan := req.Request.Cancel
|
||||
ctxDoneChan := req.Context().Done()
|
||||
pcClosed := pc.closech
|
||||
for {
|
||||
testHookWaitResLoop()
|
||||
select {
|
||||
|
|
@ -2618,11 +2619,15 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
|
|||
defer timer.Stop() // prevent leaks
|
||||
respHeaderTimer = timer.C
|
||||
}
|
||||
case <-pc.closech:
|
||||
if debugRoundTrip {
|
||||
req.logf("closech recv: %T %#v", pc.closed, pc.closed)
|
||||
case <-pcClosed:
|
||||
pcClosed = nil
|
||||
// check if we are still using the connection
|
||||
if pc.t.replaceReqCanceler(req.cancelKey, nil) {
|
||||
if debugRoundTrip {
|
||||
req.logf("closech recv: %T %#v", pc.closed, pc.closed)
|
||||
}
|
||||
return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed)
|
||||
}
|
||||
return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed)
|
||||
case <-respHeaderTimer:
|
||||
if debugRoundTrip {
|
||||
req.logf("timeout waiting for response headers.")
|
||||
|
|
|
|||
|
|
@ -6433,3 +6433,54 @@ func TestErrorWriteLoopRace(t *testing.T) {
|
|||
testTransportRace(req)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 41600
|
||||
// Test that a new request which uses the connection of an active request
|
||||
// cannot cause it to be canceled as well.
|
||||
func TestCancelRequestWhenSharingConnection(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) {
|
||||
w.Header().Add("Content-Length", "0")
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := ts.Client()
|
||||
transport := client.Transport.(*Transport)
|
||||
transport.MaxIdleConns = 1
|
||||
transport.MaxConnsPerHost = 1
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for ctx.Err() == nil {
|
||||
reqctx, reqcancel := context.WithCancel(ctx)
|
||||
go reqcancel()
|
||||
req, _ := NewRequestWithContext(reqctx, "GET", ts.URL, nil)
|
||||
res, err := client.Do(req)
|
||||
if err == nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for ctx.Err() == nil {
|
||||
req, _ := NewRequest("GET", ts.URL, nil)
|
||||
if res, err := client.Do(req); err != nil {
|
||||
t.Errorf("unexpected: %p %v", req, err)
|
||||
break
|
||||
} else {
|
||||
res.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
cancel()
|
||||
wg.Wait()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,6 +259,9 @@ func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error) {
|
|||
// ListenMulticastUDP is just for convenience of simple, small
|
||||
// applications. There are golang.org/x/net/ipv4 and
|
||||
// golang.org/x/net/ipv6 packages for general purpose uses.
|
||||
//
|
||||
// Note that ListenMulticastUDP will set the IP_MULTICAST_LOOP socket option
|
||||
// to 0 under IPPROTO_IP, to disable loopback of multicast packets.
|
||||
func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
|
||||
switch network {
|
||||
case "udp", "udp4", "udp6":
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@
|
|||
|
||||
package os
|
||||
|
||||
import "io/fs"
|
||||
import (
|
||||
"io/fs"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type readdirMode int
|
||||
|
||||
|
|
@ -103,3 +106,20 @@ func (f *File) ReadDir(n int) ([]DirEntry, error) {
|
|||
// testingForceReadDirLstat forces ReadDir to call Lstat, for testing that code path.
|
||||
// This can be difficult to provoke on some Unix systems otherwise.
|
||||
var testingForceReadDirLstat bool
|
||||
|
||||
// ReadDir reads the named directory,
|
||||
// returning all its directory entries sorted by filename.
|
||||
// If an error occurs reading the directory,
|
||||
// ReadDir returns the entries it was able to read before the error,
|
||||
// along with the error.
|
||||
func ReadDir(name string) ([]DirEntry, error) {
|
||||
f, err := Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
dirs, err := f.ReadDir(-1)
|
||||
sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
|
||||
return dirs, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -144,3 +145,98 @@ func ExampleUnsetenv() {
|
|||
os.Setenv("TMPDIR", "/my/tmp")
|
||||
defer os.Unsetenv("TMPDIR")
|
||||
}
|
||||
|
||||
func ExampleReadDir() {
|
||||
files, err := os.ReadDir(".")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
fmt.Println(file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleMkdirTemp() {
|
||||
dir, err := os.MkdirTemp("", "example")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir) // clean up
|
||||
|
||||
file := filepath.Join(dir, "tmpfile")
|
||||
if err := os.WriteFile(file, []byte("content"), 0666); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleMkdirTemp_suffix() {
|
||||
logsDir, err := os.MkdirTemp("", "*-logs")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(logsDir) // clean up
|
||||
|
||||
// Logs can be cleaned out earlier if needed by searching
|
||||
// for all directories whose suffix ends in *-logs.
|
||||
globPattern := filepath.Join(os.TempDir(), "*-logs")
|
||||
matches, err := filepath.Glob(globPattern)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to match %q: %v", globPattern, err)
|
||||
}
|
||||
|
||||
for _, match := range matches {
|
||||
if err := os.RemoveAll(match); err != nil {
|
||||
log.Printf("Failed to remove %q: %v", match, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleCreateTemp() {
|
||||
f, err := os.CreateTemp("", "example")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.Remove(f.Name()) // clean up
|
||||
|
||||
if _, err := f.Write([]byte("content")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleCreateTemp_suffix() {
|
||||
f, err := os.CreateTemp("", "example.*.txt")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.Remove(f.Name()) // clean up
|
||||
|
||||
if _, err := f.Write([]byte("content")); err != nil {
|
||||
f.Close()
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleReadFile() {
|
||||
data, err := os.ReadFile("testdata/hello")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
os.Stdout.Write(data)
|
||||
|
||||
// Output:
|
||||
// Hello, Gophers!
|
||||
}
|
||||
|
||||
func ExampleWriteFile() {
|
||||
err := os.WriteFile("testdata/hello", []byte("Hello, Gophers!"), 0666)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -691,6 +691,18 @@ func TestExtraFiles(t *testing.T) {
|
|||
c.Stdout = &stdout
|
||||
c.Stderr = &stderr
|
||||
c.ExtraFiles = []*os.File{tf}
|
||||
if runtime.GOOS == "illumos" {
|
||||
// Some facilities in illumos are implemented via access
|
||||
// to /proc by libc; such accesses can briefly occupy a
|
||||
// low-numbered fd. If this occurs concurrently with the
|
||||
// test that checks for leaked descriptors, the check can
|
||||
// become confused and report a spurious leaked descriptor.
|
||||
// (See issue #42431 for more detailed analysis.)
|
||||
//
|
||||
// Attempt to constrain the use of additional threads in the
|
||||
// child process to make this test less flaky:
|
||||
c.Env = append(os.Environ(), "GOMAXPROCS=1")
|
||||
}
|
||||
err = c.Run()
|
||||
if err != nil {
|
||||
t.Fatalf("Run: %v\n--- stdout:\n%s--- stderr:\n%s", err, stdout.Bytes(), stderr.Bytes())
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ var Atime = atime
|
|||
var LstatP = &lstat
|
||||
var ErrWriteAtInAppendMode = errWriteAtInAppendMode
|
||||
var TestingForceReadDirLstat = &testingForceReadDirLstat
|
||||
var ErrPatternHasSeparator = errPatternHasSeparator
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ func UserCacheDir() (string, error) {
|
|||
return "", errors.New("%LocalAppData% is not defined")
|
||||
}
|
||||
|
||||
case "darwin":
|
||||
case "darwin", "ios":
|
||||
dir = Getenv("HOME")
|
||||
if dir == "" {
|
||||
return "", errors.New("$HOME is not defined")
|
||||
|
|
@ -457,7 +457,7 @@ func UserConfigDir() (string, error) {
|
|||
return "", errors.New("%AppData% is not defined")
|
||||
}
|
||||
|
||||
case "darwin":
|
||||
case "darwin", "ios":
|
||||
dir = Getenv("HOME")
|
||||
if dir == "" {
|
||||
return "", errors.New("$HOME is not defined")
|
||||
|
|
@ -505,10 +505,8 @@ func UserHomeDir() (string, error) {
|
|||
switch runtime.GOOS {
|
||||
case "android":
|
||||
return "/sdcard", nil
|
||||
case "darwin":
|
||||
if runtime.GOARCH == "arm64" {
|
||||
return "/", nil
|
||||
}
|
||||
case "ios":
|
||||
return "/", nil
|
||||
}
|
||||
return "", errors.New(enverr + " is not defined")
|
||||
}
|
||||
|
|
@ -627,3 +625,63 @@ func (dir dirFS) Open(name string) (fs.File, error) {
|
|||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// ReadFile reads the named file and returns the contents.
|
||||
// A successful call returns err == nil, not err == EOF.
|
||||
// Because ReadFile reads the whole file, it does not treat an EOF from Read
|
||||
// as an error to be reported.
|
||||
func ReadFile(name string) ([]byte, error) {
|
||||
f, err := Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var size int
|
||||
if info, err := f.Stat(); err == nil {
|
||||
size64 := info.Size()
|
||||
if int64(int(size64)) == size64 {
|
||||
size = int(size64)
|
||||
}
|
||||
}
|
||||
size++ // one byte for final read at EOF
|
||||
|
||||
// If a file claims a small size, read at least 512 bytes.
|
||||
// In particular, files in Linux's /proc claim size 0 but
|
||||
// then do not work right if read in small pieces,
|
||||
// so an initial read of 1 byte would not work correctly.
|
||||
if size < 512 {
|
||||
size = 512
|
||||
}
|
||||
|
||||
data := make([]byte, 0, size)
|
||||
for {
|
||||
if len(data) >= cap(data) {
|
||||
d := append(data[:cap(data)], 0)
|
||||
data = d[:len(data)]
|
||||
}
|
||||
n, err := f.Read(data[len(data):cap(data)])
|
||||
data = data[:len(data)+n]
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WriteFile writes data to the named file, creating it if necessary.
|
||||
// If the file does not exist, WriteFile creates it with permissions perm (before umask);
|
||||
// otherwise WriteFile truncates it before writing, without changing permissions.
|
||||
func WriteFile(name string, data []byte, perm FileMode) error {
|
||||
f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(data)
|
||||
if err1 := f.Close(); err1 != nil && err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -419,19 +419,19 @@ func testReadDir(dir string, contents []string, t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestReaddirnames(t *testing.T) {
|
||||
func TestFileReaddirnames(t *testing.T) {
|
||||
testReaddirnames(".", dot, t)
|
||||
testReaddirnames(sysdir.name, sysdir.files, t)
|
||||
testReaddirnames(t.TempDir(), nil, t)
|
||||
}
|
||||
|
||||
func TestReaddir(t *testing.T) {
|
||||
func TestFileReaddir(t *testing.T) {
|
||||
testReaddir(".", dot, t)
|
||||
testReaddir(sysdir.name, sysdir.files, t)
|
||||
testReaddir(t.TempDir(), nil, t)
|
||||
}
|
||||
|
||||
func TestReadDir(t *testing.T) {
|
||||
func TestFileReadDir(t *testing.T) {
|
||||
testReadDir(".", dot, t)
|
||||
testReadDir(sysdir.name, sysdir.files, t)
|
||||
testReadDir(t.TempDir(), nil, t)
|
||||
|
|
@ -1235,6 +1235,7 @@ func TestChmod(t *testing.T) {
|
|||
}
|
||||
|
||||
func checkSize(t *testing.T, f *File, size int64) {
|
||||
t.Helper()
|
||||
dir, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
|
||||
|
|
@ -2690,3 +2691,22 @@ func TestDirFS(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadFileProc(t *testing.T) {
|
||||
// Linux files in /proc report 0 size,
|
||||
// but then if ReadFile reads just a single byte at offset 0,
|
||||
// the read at offset 1 returns EOF instead of more data.
|
||||
// ReadFile has a minimum read size of 512 to work around this,
|
||||
// but test explicitly that it's working.
|
||||
name := "/proc/sys/fs/pipe-max-size"
|
||||
if _, err := Stat(name); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
data, err := ReadFile(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(data) == 0 || data[len(data)-1] != '\n' {
|
||||
t.Fatalf("read %s: not newline-terminated: %q", name, data)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
127
src/os/read_test.go
Normal file
127
src/os/read_test.go
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2009 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 os_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
. "os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func checkNamedSize(t *testing.T, path string, size int64) {
|
||||
dir, err := Stat(path)
|
||||
if err != nil {
|
||||
t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
|
||||
}
|
||||
if dir.Size() != size {
|
||||
t.Errorf("Stat %q: size %d want %d", path, dir.Size(), size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadFile(t *testing.T) {
|
||||
filename := "rumpelstilzchen"
|
||||
contents, err := ReadFile(filename)
|
||||
if err == nil {
|
||||
t.Fatalf("ReadFile %s: error expected, none found", filename)
|
||||
}
|
||||
|
||||
filename = "read_test.go"
|
||||
contents, err = ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile %s: %v", filename, err)
|
||||
}
|
||||
|
||||
checkNamedSize(t, filename, int64(len(contents)))
|
||||
}
|
||||
|
||||
func TestWriteFile(t *testing.T) {
|
||||
f, err := CreateTemp("", "ioutil-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
defer Remove(f.Name())
|
||||
|
||||
msg := "Programming today is a race between software engineers striving to " +
|
||||
"build bigger and better idiot-proof programs, and the Universe trying " +
|
||||
"to produce bigger and better idiots. So far, the Universe is winning."
|
||||
|
||||
if err := WriteFile(f.Name(), []byte(msg), 0644); err != nil {
|
||||
t.Fatalf("WriteFile %s: %v", f.Name(), err)
|
||||
}
|
||||
|
||||
data, err := ReadFile(f.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile %s: %v", f.Name(), err)
|
||||
}
|
||||
|
||||
if string(data) != msg {
|
||||
t.Fatalf("ReadFile: wrong data:\nhave %q\nwant %q", string(data), msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadOnlyWriteFile(t *testing.T) {
|
||||
if Getuid() == 0 {
|
||||
t.Skipf("Root can write to read-only files anyway, so skip the read-only test.")
|
||||
}
|
||||
|
||||
// We don't want to use CreateTemp directly, since that opens a file for us as 0600.
|
||||
tempDir, err := MkdirTemp("", t.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer RemoveAll(tempDir)
|
||||
filename := filepath.Join(tempDir, "blurp.txt")
|
||||
|
||||
shmorp := []byte("shmorp")
|
||||
florp := []byte("florp")
|
||||
err = WriteFile(filename, shmorp, 0444)
|
||||
if err != nil {
|
||||
t.Fatalf("WriteFile %s: %v", filename, err)
|
||||
}
|
||||
err = WriteFile(filename, florp, 0444)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an error when writing to read-only file %s", filename)
|
||||
}
|
||||
got, err := ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile %s: %v", filename, err)
|
||||
}
|
||||
if !bytes.Equal(got, shmorp) {
|
||||
t.Fatalf("want %s, got %s", shmorp, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadDir(t *testing.T) {
|
||||
dirname := "rumpelstilzchen"
|
||||
_, err := ReadDir(dirname)
|
||||
if err == nil {
|
||||
t.Fatalf("ReadDir %s: error expected, none found", dirname)
|
||||
}
|
||||
|
||||
dirname = "."
|
||||
list, err := ReadDir(dirname)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDir %s: %v", dirname, err)
|
||||
}
|
||||
|
||||
foundFile := false
|
||||
foundSubDir := false
|
||||
for _, dir := range list {
|
||||
switch {
|
||||
case !dir.IsDir() && dir.Name() == "read_test.go":
|
||||
foundFile = true
|
||||
case dir.IsDir() && dir.Name() == "exec":
|
||||
foundSubDir = true
|
||||
}
|
||||
}
|
||||
if !foundFile {
|
||||
t.Fatalf("ReadDir %s: read_test.go file not found", dirname)
|
||||
}
|
||||
if !foundSubDir {
|
||||
t.Fatalf("ReadDir %s: exec directory not found", dirname)
|
||||
}
|
||||
}
|
||||
|
|
@ -355,11 +355,12 @@ func TestRemoveAllButReadOnlyAndPathError(t *testing.T) {
|
|||
// The error should be of type *PathError.
|
||||
// see issue 30491 for details.
|
||||
if pathErr, ok := err.(*PathError); ok {
|
||||
if g, w := pathErr.Path, filepath.Join(tempDir, "b", "y"); g != w {
|
||||
t.Errorf("got %q, expected pathErr.path %q", g, w)
|
||||
want := filepath.Join(tempDir, "b", "y")
|
||||
if pathErr.Path != want {
|
||||
t.Errorf("RemoveAll(%q): err.Path=%q, want %q", tempDir, pathErr.Path, want)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("got %T, expected *fs.PathError", err)
|
||||
t.Errorf("RemoveAll(%q): error has type %T, want *fs.PathError", tempDir, err)
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
|
|
|
|||
118
src/os/tempfile.go
Normal file
118
src/os/tempfile.go
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2010 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 os
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// fastrand provided by runtime.
|
||||
// We generate random temporary file names so that there's a good
|
||||
// chance the file doesn't exist yet - keeps the number of tries in
|
||||
// TempFile to a minimum.
|
||||
func fastrand() uint32
|
||||
|
||||
func nextRandom() string {
|
||||
return uitoa(uint(fastrand()))
|
||||
}
|
||||
|
||||
// CreateTemp creates a new temporary file in the directory dir,
|
||||
// opens the file for reading and writing, and returns the resulting file.
|
||||
// The filename is generated by taking pattern and adding a random string to the end.
|
||||
// If pattern includes a "*", the random string replaces the last "*".
|
||||
// If dir is the empty string, TempFile uses the default directory for temporary files, as returned by TempDir.
|
||||
// Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file.
|
||||
// The caller can use the file's Name method to find the pathname of the file.
|
||||
// It is the caller's responsibility to remove the file when it is no longer needed.
|
||||
func CreateTemp(dir, pattern string) (*File, error) {
|
||||
if dir == "" {
|
||||
dir = TempDir()
|
||||
}
|
||||
|
||||
prefix, suffix, err := prefixAndSuffix(pattern)
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "createtemp", Path: pattern, Err: err}
|
||||
}
|
||||
prefix = joinPath(dir, prefix)
|
||||
|
||||
try := 0
|
||||
for {
|
||||
name := prefix + nextRandom() + suffix
|
||||
f, err := OpenFile(name, O_RDWR|O_CREATE|O_EXCL, 0600)
|
||||
if IsExist(err) {
|
||||
if try++; try < 10000 {
|
||||
continue
|
||||
}
|
||||
return nil, &PathError{Op: "createtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist}
|
||||
}
|
||||
return f, err
|
||||
}
|
||||
}
|
||||
|
||||
var errPatternHasSeparator = errors.New("pattern contains path separator")
|
||||
|
||||
// prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
|
||||
// returning prefix as the part before "*" and suffix as the part after "*".
|
||||
func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
|
||||
for i := 0; i < len(pattern); i++ {
|
||||
if IsPathSeparator(pattern[i]) {
|
||||
return "", "", errPatternHasSeparator
|
||||
}
|
||||
}
|
||||
if pos := strings.LastIndex(pattern, "*"); pos != -1 {
|
||||
prefix, suffix = pattern[:pos], pattern[pos+1:]
|
||||
} else {
|
||||
prefix = pattern
|
||||
}
|
||||
return prefix, suffix, nil
|
||||
}
|
||||
|
||||
// MkdirTemp creates a new temporary directory in the directory dir
|
||||
// and returns the pathname of the new directory.
|
||||
// The new directory's name is generated by adding a random string to the end of pattern.
|
||||
// If pattern includes a "*", the random string replaces the last "*" instead.
|
||||
// If dir is the empty string, TempFile uses the default directory for temporary files, as returned by TempDir.
|
||||
// Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
|
||||
// It is the caller's responsibility to remove the directory when it is no longer needed.
|
||||
func MkdirTemp(dir, pattern string) (string, error) {
|
||||
if dir == "" {
|
||||
dir = TempDir()
|
||||
}
|
||||
|
||||
prefix, suffix, err := prefixAndSuffix(pattern)
|
||||
if err != nil {
|
||||
return "", &PathError{Op: "mkdirtemp", Path: pattern, Err: err}
|
||||
}
|
||||
prefix = joinPath(dir, prefix)
|
||||
|
||||
try := 0
|
||||
for {
|
||||
name := prefix + nextRandom() + suffix
|
||||
err := Mkdir(name, 0700)
|
||||
if err == nil {
|
||||
return name, nil
|
||||
}
|
||||
if IsExist(err) {
|
||||
if try++; try < 10000 {
|
||||
continue
|
||||
}
|
||||
return "", &PathError{Op: "mkdirtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist}
|
||||
}
|
||||
if IsNotExist(err) {
|
||||
if _, err := Stat(dir); IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
func joinPath(dir, name string) string {
|
||||
if len(dir) > 0 && IsPathSeparator(dir[len(dir)-1]) {
|
||||
return dir + name
|
||||
}
|
||||
return dir + string(PathSeparator) + name
|
||||
}
|
||||
193
src/os/tempfile_test.go
Normal file
193
src/os/tempfile_test.go
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
// Copyright 2010 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 os_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
. "os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateTemp(t *testing.T) {
|
||||
dir, err := MkdirTemp("", "TestCreateTempBadDir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer RemoveAll(dir)
|
||||
|
||||
nonexistentDir := filepath.Join(dir, "_not_exists_")
|
||||
f, err := CreateTemp(nonexistentDir, "foo")
|
||||
if f != nil || err == nil {
|
||||
t.Errorf("CreateTemp(%q, `foo`) = %v, %v", nonexistentDir, f, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateTempPattern(t *testing.T) {
|
||||
tests := []struct{ pattern, prefix, suffix string }{
|
||||
{"tempfile_test", "tempfile_test", ""},
|
||||
{"tempfile_test*", "tempfile_test", ""},
|
||||
{"tempfile_test*xyz", "tempfile_test", "xyz"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
f, err := CreateTemp("", test.pattern)
|
||||
if err != nil {
|
||||
t.Errorf("CreateTemp(..., %q) error: %v", test.pattern, err)
|
||||
continue
|
||||
}
|
||||
defer Remove(f.Name())
|
||||
base := filepath.Base(f.Name())
|
||||
f.Close()
|
||||
if !(strings.HasPrefix(base, test.prefix) && strings.HasSuffix(base, test.suffix)) {
|
||||
t.Errorf("CreateTemp pattern %q created bad name %q; want prefix %q & suffix %q",
|
||||
test.pattern, base, test.prefix, test.suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateTempBadPattern(t *testing.T) {
|
||||
tmpDir, err := MkdirTemp("", t.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer RemoveAll(tmpDir)
|
||||
|
||||
const sep = string(PathSeparator)
|
||||
tests := []struct {
|
||||
pattern string
|
||||
wantErr bool
|
||||
}{
|
||||
{"ioutil*test", false},
|
||||
{"tempfile_test*foo", false},
|
||||
{"tempfile_test" + sep + "foo", true},
|
||||
{"tempfile_test*" + sep + "foo", true},
|
||||
{"tempfile_test" + sep + "*foo", true},
|
||||
{sep + "tempfile_test" + sep + "*foo", true},
|
||||
{"tempfile_test*foo" + sep, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.pattern, func(t *testing.T) {
|
||||
tmpfile, err := CreateTemp(tmpDir, tt.pattern)
|
||||
if tmpfile != nil {
|
||||
defer tmpfile.Close()
|
||||
}
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("CreateTemp(..., %#q) succeeded, expected error", tt.pattern)
|
||||
}
|
||||
if !errors.Is(err, ErrPatternHasSeparator) {
|
||||
t.Errorf("CreateTemp(..., %#q): %v, expected ErrPatternHasSeparator", tt.pattern, err)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Errorf("CreateTemp(..., %#q): %v", tt.pattern, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMkdirTemp(t *testing.T) {
|
||||
name, err := MkdirTemp("/_not_exists_", "foo")
|
||||
if name != "" || err == nil {
|
||||
t.Errorf("MkdirTemp(`/_not_exists_`, `foo`) = %v, %v", name, err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
pattern string
|
||||
wantPrefix, wantSuffix string
|
||||
}{
|
||||
{"tempfile_test", "tempfile_test", ""},
|
||||
{"tempfile_test*", "tempfile_test", ""},
|
||||
{"tempfile_test*xyz", "tempfile_test", "xyz"},
|
||||
}
|
||||
|
||||
dir := filepath.Clean(TempDir())
|
||||
|
||||
runTestMkdirTemp := func(t *testing.T, pattern, wantRePat string) {
|
||||
name, err := MkdirTemp(dir, pattern)
|
||||
if name == "" || err != nil {
|
||||
t.Fatalf("MkdirTemp(dir, `tempfile_test`) = %v, %v", name, err)
|
||||
}
|
||||
defer Remove(name)
|
||||
|
||||
re := regexp.MustCompile(wantRePat)
|
||||
if !re.MatchString(name) {
|
||||
t.Errorf("MkdirTemp(%q, %q) created bad name\n\t%q\ndid not match pattern\n\t%q", dir, pattern, name, wantRePat)
|
||||
}
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.pattern, func(t *testing.T) {
|
||||
wantRePat := "^" + regexp.QuoteMeta(filepath.Join(dir, tt.wantPrefix)) + "[0-9]+" + regexp.QuoteMeta(tt.wantSuffix) + "$"
|
||||
runTestMkdirTemp(t, tt.pattern, wantRePat)
|
||||
})
|
||||
}
|
||||
|
||||
// Separately testing "*xyz" (which has no prefix). That is when constructing the
|
||||
// pattern to assert on, as in the previous loop, using filepath.Join for an empty
|
||||
// prefix filepath.Join(dir, ""), produces the pattern:
|
||||
// ^<DIR>[0-9]+xyz$
|
||||
// yet we just want to match
|
||||
// "^<DIR>/[0-9]+xyz"
|
||||
t.Run("*xyz", func(t *testing.T) {
|
||||
wantRePat := "^" + regexp.QuoteMeta(filepath.Join(dir)) + regexp.QuoteMeta(string(filepath.Separator)) + "[0-9]+xyz$"
|
||||
runTestMkdirTemp(t, "*xyz", wantRePat)
|
||||
})
|
||||
}
|
||||
|
||||
// test that we return a nice error message if the dir argument to TempDir doesn't
|
||||
// exist (or that it's empty and TempDir doesn't exist)
|
||||
func TestMkdirTempBadDir(t *testing.T) {
|
||||
dir, err := MkdirTemp("", "MkdirTempBadDir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer RemoveAll(dir)
|
||||
|
||||
badDir := filepath.Join(dir, "not-exist")
|
||||
_, err = MkdirTemp(badDir, "foo")
|
||||
if pe, ok := err.(*fs.PathError); !ok || !IsNotExist(err) || pe.Path != badDir {
|
||||
t.Errorf("TempDir error = %#v; want PathError for path %q satisifying IsNotExist", err, badDir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMkdirTempBadPattern(t *testing.T) {
|
||||
tmpDir, err := MkdirTemp("", t.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer RemoveAll(tmpDir)
|
||||
|
||||
const sep = string(PathSeparator)
|
||||
tests := []struct {
|
||||
pattern string
|
||||
wantErr bool
|
||||
}{
|
||||
{"ioutil*test", false},
|
||||
{"tempfile_test*foo", false},
|
||||
{"tempfile_test" + sep + "foo", true},
|
||||
{"tempfile_test*" + sep + "foo", true},
|
||||
{"tempfile_test" + sep + "*foo", true},
|
||||
{sep + "tempfile_test" + sep + "*foo", true},
|
||||
{"tempfile_test*foo" + sep, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.pattern, func(t *testing.T) {
|
||||
_, err := MkdirTemp(tmpDir, tt.pattern)
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("MkdirTemp(..., %#q) succeeded, expected error", tt.pattern)
|
||||
}
|
||||
if !errors.Is(err, ErrPatternHasSeparator) {
|
||||
t.Errorf("MkdirTemp(..., %#q): %v, expected ErrPatternHasSeparator", tt.pattern, err)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Errorf("MkdirTemp(..., %#q): %v", tt.pattern, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
1
src/os/testdata/hello
vendored
Normal file
1
src/os/testdata/hello
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
Hello, Gophers!
|
||||
|
|
@ -4007,9 +4007,12 @@ var convertTests = []struct {
|
|||
{V(int16(-3)), V(string("\uFFFD"))},
|
||||
{V(int32(-4)), V(string("\uFFFD"))},
|
||||
{V(int64(-5)), V(string("\uFFFD"))},
|
||||
{V(int64(-1 << 32)), V(string("\uFFFD"))},
|
||||
{V(int64(1 << 32)), V(string("\uFFFD"))},
|
||||
{V(uint(0x110001)), V(string("\uFFFD"))},
|
||||
{V(uint32(0x110002)), V(string("\uFFFD"))},
|
||||
{V(uint64(0x110003)), V(string("\uFFFD"))},
|
||||
{V(uint64(1 << 32)), V(string("\uFFFD"))},
|
||||
{V(uintptr(0x110004)), V(string("\uFFFD"))},
|
||||
|
||||
// named string
|
||||
|
|
|
|||
|
|
@ -2681,12 +2681,20 @@ func cvtComplex(v Value, t Type) Value {
|
|||
|
||||
// convertOp: intXX -> string
|
||||
func cvtIntString(v Value, t Type) Value {
|
||||
return makeString(v.flag.ro(), string(rune(v.Int())), t)
|
||||
s := "\uFFFD"
|
||||
if x := v.Int(); int64(rune(x)) == x {
|
||||
s = string(rune(x))
|
||||
}
|
||||
return makeString(v.flag.ro(), s, t)
|
||||
}
|
||||
|
||||
// convertOp: uintXX -> string
|
||||
func cvtUintString(v Value, t Type) Value {
|
||||
return makeString(v.flag.ro(), string(rune(v.Uint())), t)
|
||||
s := "\uFFFD"
|
||||
if x := v.Uint(); uint64(rune(x)) == x {
|
||||
s = string(rune(x))
|
||||
}
|
||||
return makeString(v.flag.ro(), s, t)
|
||||
}
|
||||
|
||||
// convertOp: []byte -> string
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ func TestPanicSystemstack(t *testing.T) {
|
|||
// we don't have a way to know when it is fully blocked, sleep a bit to
|
||||
// make us less likely to lose the race and signal before the child
|
||||
// blocks.
|
||||
time.Sleep(100*time.Millisecond)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Send SIGQUIT.
|
||||
if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil {
|
||||
|
|
|
|||
|
|
@ -283,6 +283,12 @@ func libpreinit() {
|
|||
func mpreinit(mp *m) {
|
||||
mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
|
||||
mp.gsignal.m = mp
|
||||
if GOOS == "darwin" && GOARCH == "arm64" {
|
||||
// mlock the signal stack to work around a kernel bug where it may
|
||||
// SIGILL when the signal stack is not faulted in while a signal
|
||||
// arrives. See issue 42774.
|
||||
mlock(unsafe.Pointer(mp.gsignal.stack.hi-physPageSize), physPageSize)
|
||||
}
|
||||
}
|
||||
|
||||
// Called to initialize a new m (including the bootstrap m).
|
||||
|
|
|
|||
|
|
@ -286,6 +286,10 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri
|
|||
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
|
||||
broken = true
|
||||
}
|
||||
case "windows":
|
||||
if runtime.GOARCH == "arm" {
|
||||
broken = true // See https://golang.org/issues/42862
|
||||
}
|
||||
}
|
||||
|
||||
maxDuration := 5 * time.Second
|
||||
|
|
|
|||
|
|
@ -43,16 +43,9 @@ func initExceptionHandler() {
|
|||
//
|
||||
//go:nosplit
|
||||
func isAbort(r *context) bool {
|
||||
switch GOARCH {
|
||||
case "386", "amd64":
|
||||
// In the case of an abort, the exception IP is one byte after
|
||||
// the INT3 (this differs from UNIX OSes).
|
||||
return isAbortPC(r.ip() - 1)
|
||||
case "arm":
|
||||
return isAbortPC(r.ip())
|
||||
default:
|
||||
return false
|
||||
}
|
||||
// In the case of an abort, the exception IP is one byte after
|
||||
// the INT3 (this differs from UNIX OSes).
|
||||
return isAbortPC(r.ip() - 1)
|
||||
}
|
||||
|
||||
// isgoexception reports whether this exception should be translated
|
||||
|
|
|
|||
|
|
@ -133,6 +133,9 @@ func sync_fastrand() uint32 { return fastrand() }
|
|||
//go:linkname net_fastrand net.fastrand
|
||||
func net_fastrand() uint32 { return fastrand() }
|
||||
|
||||
//go:linkname os_fastrand os.fastrand
|
||||
func os_fastrand() uint32 { return fastrand() }
|
||||
|
||||
// in internal/bytealg/equal_*.s
|
||||
//go:noescape
|
||||
func memequal(a, b unsafe.Pointer, size uintptr) bool
|
||||
|
|
|
|||
|
|
@ -226,6 +226,13 @@ func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
|
|||
}
|
||||
func madvise_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func mlock(addr unsafe.Pointer, n uintptr) {
|
||||
libcCall(unsafe.Pointer(funcPC(mlock_trampoline)), unsafe.Pointer(&addr))
|
||||
}
|
||||
func mlock_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func read(fd int32, p unsafe.Pointer, n int32) int32 {
|
||||
|
|
@ -465,6 +472,7 @@ func setNonblock(fd int32) {
|
|||
//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic libc_madvise madvise "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic libc_mlock mlock "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic libc_error __error "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic libc_usleep usleep "/usr/lib/libSystem.B.dylib"
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
|
|||
POPQ BP
|
||||
RET
|
||||
|
||||
TEXT runtime·mlock_trampoline(SB), NOSPLIT, $0
|
||||
UNDEF // unimplemented
|
||||
|
||||
GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
|
||||
|
||||
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
|
||||
|
|
|
|||
|
|
@ -120,6 +120,12 @@ TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
|
|||
BL libc_madvise(SB)
|
||||
RET
|
||||
|
||||
TEXT runtime·mlock_trampoline(SB),NOSPLIT,$0
|
||||
MOVD 8(R0), R1 // arg 2 len
|
||||
MOVD 0(R0), R0 // arg 1 addr
|
||||
BL libc_mlock(SB)
|
||||
RET
|
||||
|
||||
TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
|
||||
MOVD 8(R0), R1 // arg 2 new
|
||||
MOVD 16(R0), R2 // arg 3 old
|
||||
|
|
|
|||
|
|
@ -969,8 +969,9 @@ func TestDLLPreloadMitigation(t *testing.T) {
|
|||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
uintptr_t cfunc() {
|
||||
uintptr_t cfunc(void) {
|
||||
SetLastError(123);
|
||||
return 0;
|
||||
}
|
||||
`
|
||||
srcname := "nojack.c"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ var t struct {
|
|||
_ int
|
||||
}
|
||||
|
||||
func (x int) _() { // ERROR "cannot define new methods on non-local type"
|
||||
func (x int) _() { // ERROR "methods on non-local type"
|
||||
println(x)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ func main() {
|
|||
cs = cr // ERROR "illegal types|incompatible|cannot"
|
||||
|
||||
var n int
|
||||
<-n // ERROR "receive from non-chan"
|
||||
n <- 2 // ERROR "send to non-chan"
|
||||
<-n // ERROR "receive from non-chan|expected channel"
|
||||
n <- 2 // ERROR "send to non-chan|must be channel"
|
||||
|
||||
c <- 0 // ok
|
||||
<-c // ok
|
||||
|
|
@ -66,5 +66,5 @@ func main() {
|
|||
close(c)
|
||||
close(cs)
|
||||
close(cr) // ERROR "receive"
|
||||
close(n) // ERROR "invalid operation.*non-chan type"
|
||||
close(n) // ERROR "invalid operation.*non-chan type|must be channel"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ var (
|
|||
_ = m[0][:] // ERROR "slice of unaddressable value"
|
||||
_ = f()[:] // ERROR "slice of unaddressable value"
|
||||
|
||||
_ = 301[:] // ERROR "cannot slice"
|
||||
_ = 3.1[:] // ERROR "cannot slice"
|
||||
_ = true[:] // ERROR "cannot slice"
|
||||
_ = 301[:] // ERROR "cannot slice|attempt to slice object that is not"
|
||||
_ = 3.1[:] // ERROR "cannot slice|attempt to slice object that is not"
|
||||
_ = true[:] // ERROR "cannot slice|attempt to slice object that is not"
|
||||
|
||||
// these are okay because they are slicing a pointer to an array
|
||||
_ = (&[3]int{1, 2, 3})[:]
|
||||
|
|
@ -46,8 +46,8 @@ var (
|
|||
_ = &T{0, 0, "", nil} // ok
|
||||
_ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal"
|
||||
_ = &T{0, 0, "", {}} // ERROR "missing type in composite literal|omit types within composite literal"
|
||||
_ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP"
|
||||
_ = &Ti{} // ERROR "invalid composite literal type Ti"
|
||||
_ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP|omit types within composite literal"
|
||||
_ = &Ti{} // ERROR "invalid composite literal type Ti|expected.*type for composite literal"
|
||||
)
|
||||
|
||||
type M map[T]T
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ var x6 = int(1e100) // ERROR "overflow"
|
|||
var x7 = float32(1e1000) // ERROR "overflow"
|
||||
|
||||
// unsafe.Pointer can only convert to/from uintptr
|
||||
var _ = string(unsafe.Pointer(uintptr(65))) // ERROR "convert"
|
||||
var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert"
|
||||
var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert"
|
||||
var _ = string(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
|
||||
var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
|
||||
var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion"
|
||||
|
||||
// implicit conversions merit scrutiny
|
||||
var s string
|
||||
|
|
|
|||
|
|
@ -60,5 +60,5 @@ func bad(args ...int) {
|
|||
_ = [...]byte("foo") // ERROR "[.][.][.]"
|
||||
_ = [...][...]int{{1,2,3},{4,5,6}} // ERROR "[.][.][.]"
|
||||
|
||||
Foo(x...) // ERROR "invalid use of [.][.][.] in call"
|
||||
Foo(x...) // ERROR "invalid use of .*[.][.][.]"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ package main
|
|||
var x int
|
||||
|
||||
var a = []int{ x: 1} // ERROR "constant"
|
||||
var b = [...]int{x: 1}
|
||||
var b = [...]int{x: 1} // GCCGO_ERROR "constant"
|
||||
var c = map[int]int{ x: 1}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,4 +14,4 @@ func main() {}
|
|||
|
||||
// important: no newline on end of next line.
|
||||
// 6g used to print <epoch> instead of bug332.go:111
|
||||
func (t *T) F() {} // ERROR "undefined: T"
|
||||
func (t *T) F() {} // ERROR "undefined.*T"
|
||||
|
|
@ -13,6 +13,6 @@ func main() {
|
|||
switch t := x.(type) {
|
||||
case 0: // ERROR "type"
|
||||
t.x = 1
|
||||
x.x = 1 // ERROR "type interface \{\}|reference to undefined field or method"
|
||||
x.x = 1 // ERROR "type interface \{\}|reference to undefined field or method|interface with no methods"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ func f() {
|
|||
_ = a[10:10]
|
||||
_ = a[9:12] // ERROR "invalid slice index 12|index out of bounds"
|
||||
_ = a[11:12] // ERROR "invalid slice index 11|index out of bounds"
|
||||
_ = a[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds"
|
||||
_ = a[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds"
|
||||
|
||||
var s []int
|
||||
_ = s[-1] // ERROR "invalid slice index -1|index out of bounds"
|
||||
|
|
@ -30,7 +30,7 @@ func f() {
|
|||
_ = s[10:10]
|
||||
_ = s[9:12]
|
||||
_ = s[11:12]
|
||||
_ = s[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds"
|
||||
_ = s[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds"
|
||||
|
||||
const c = "foofoofoof"
|
||||
_ = c[-1] // ERROR "invalid string index -1|index out of bounds"
|
||||
|
|
@ -41,7 +41,7 @@ func f() {
|
|||
_ = c[10:10]
|
||||
_ = c[9:12] // ERROR "invalid slice index 12|index out of bounds"
|
||||
_ = c[11:12] // ERROR "invalid slice index 11|index out of bounds"
|
||||
_ = c[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds"
|
||||
_ = c[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds"
|
||||
|
||||
var t string
|
||||
_ = t[-1] // ERROR "invalid string index -1|index out of bounds"
|
||||
|
|
@ -52,5 +52,5 @@ func f() {
|
|||
_ = t[10:10]
|
||||
_ = t[9:12]
|
||||
_ = t[11:12]
|
||||
_ = t[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds"
|
||||
_ = t[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds"
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue