mirror of
https://github.com/golang/go
synced 2024-10-06 08:00:07 +00:00
[dev.typeparams] all: merge master (16e82be
) into dev.typeparams
Merge List: + 2021-06-2116e82be454
runtime: fix crash during VDSO calls on PowerPC + 2021-06-212e542c3c06
runtime/pprof: deflake TestMorestack more + 2021-06-21ced0fdbad0
doc/go1.17: note deprecation of 'go get' for installing commands + 2021-06-217a5e7047a4
doc/go1.17: add Go 1.18 pre-announcements + 2021-06-2185a2e24afd
doc/go1.17: add security-related release notes + 2021-06-211de332996c
doc/go1.17: document go/parser.SkipObjectResolution + 2021-06-21117ebe0f52
cmd/go: do not require the module cache to exist for 'go mod edit' + 2021-06-20460900a7b5
os/signal: test with a significantly longer fatal timeout + 2021-06-19b73cc4b02b
database/sql: do not rely on timeout for deadlock test + 2021-06-1886743e7d86
image: add RGBA64Image interface + 2021-06-189401172166
runtime: clarify Frames.Next documentation + 2021-06-1857aaa19aae
runtime: disable CPU profiling before removing the SIGPROF handler + 2021-06-186f22d2c682
doc/go1.17: fix typo + 2021-06-1745f251ad6c
cmd/pprof,runtime/pprof: disable test on more broken platforms + 2021-06-17ed834853ad
cmd/go: replace a TODO with an explanatory comment + 2021-06-174dede02550
cmd/pprof: make ObjAddr a no-op + 2021-06-1797cee43c93
testing: drop unusual characters from TempDir directory name + 2021-06-17b0355a3e72
time: fix receiver for Time.IsDST method + 2021-06-17881b6ea7ba
doc/go1.17: fix redundant space + 2021-06-160e67ce3d28
cmd/go: in lazy modules, add transitive imports for 'go get' arguments + 2021-06-166ea2af0890
cmd/go: add a regression test for #45979 + 2021-06-16a294e4e798
math/rand: mention half-open intervals explicitly + 2021-06-16a6a853f94c
cmd/asm: restore supporting of *1 scaling on ARM64 Change-Id: Ifdcb817fd44b4fa9c477042b41da55d1d769b016
This commit is contained in:
commit
d626ba27bb
|
@ -28,6 +28,38 @@ pkg encoding/csv, method (*Reader) FieldPos(int) (int, int)
|
|||
pkg go/build, type Context struct, ToolTags []string
|
||||
pkg go/parser, const SkipObjectResolution = 64
|
||||
pkg go/parser, const SkipObjectResolution Mode
|
||||
pkg image, method (*Alpha) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Alpha) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*Alpha16) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Alpha16) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*CMYK) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*CMYK) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*Gray) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Gray) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*Gray16) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Gray16) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*NRGBA) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*NRGBA) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*NRGBA64) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*NRGBA64) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*NYCbCrA) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Paletted) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*Paletted) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*RGBA) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, method (*RGBA) SetRGBA64(int, int, color.RGBA64)
|
||||
pkg image, method (*YCbCr) RGBA64At(int, int) color.RGBA64
|
||||
pkg image, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At }
|
||||
pkg image, type RGBA64Image interface, At(int, int) color.Color
|
||||
pkg image, type RGBA64Image interface, Bounds() Rectangle
|
||||
pkg image, type RGBA64Image interface, ColorModel() color.Model
|
||||
pkg image, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64
|
||||
pkg image/draw, type RGBA64Image interface { At, Bounds, ColorModel, RGBA64At, Set, SetRGBA64 }
|
||||
pkg image/draw, type RGBA64Image interface, At(int, int) color.Color
|
||||
pkg image/draw, type RGBA64Image interface, Bounds() image.Rectangle
|
||||
pkg image/draw, type RGBA64Image interface, ColorModel() color.Model
|
||||
pkg image/draw, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64
|
||||
pkg image/draw, type RGBA64Image interface, Set(int, int, color.Color)
|
||||
pkg image/draw, type RGBA64Image interface, SetRGBA64(int, int, color.RGBA64)
|
||||
pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry
|
||||
pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368
|
||||
pkg math, const MaxInt = 9223372036854775807
|
||||
|
@ -153,7 +185,7 @@ pkg time, const Layout = "01/02 03:04:05PM '06 -0700"
|
|||
pkg time, const Layout ideal-string
|
||||
pkg time, func UnixMicro(int64) Time
|
||||
pkg time, func UnixMilli(int64) Time
|
||||
pkg time, method (*Time) IsDST() bool
|
||||
pkg time, method (Time) GoString() string
|
||||
pkg time, method (Time) IsDST() bool
|
||||
pkg time, method (Time) UnixMicro() int64
|
||||
pkg time, method (Time) UnixMilli() int64
|
||||
|
|
178
doc/go1.17.html
178
doc/go1.17.html
|
@ -162,7 +162,7 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
By default, <code>go</code> <code>mod</code> <code>tidy</code> verifies that
|
||||
the selected versions of dependencies relevant to the main module are the same
|
||||
versions that would be used by the prior Go release (Go 1.16 for a module that
|
||||
spsecifies <code>go</code> <code>1.17</code>), and preserves
|
||||
specifies <code>go</code> <code>1.17</code>), and preserves
|
||||
the <code>go.sum</code> entries needed by that release even for dependencies
|
||||
that are not normally needed by other commands.
|
||||
</p>
|
||||
|
@ -214,6 +214,16 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<code>environment</code> for details.
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/43684 -->
|
||||
<code>go</code> <code>get</code> prints a deprecation warning when installing
|
||||
commands outside the main module (without the <code>-d</code> flag).
|
||||
<code>go</code> <code>install</code> <code>cmd@version</code> should be used
|
||||
instead to install a command at a specific version, using a suffix like
|
||||
<code>@latest</code> or <code>@v1.2.3</code>. In Go 1.18, the <code>-d</code>
|
||||
flag will always be enabled, and <code>go</code> <code>get</code> will only
|
||||
be used to change dependencies in <code>go.mod</code>.
|
||||
</p>
|
||||
|
||||
<h4 id="missing-go-directive"><code>go.mod</code> files missing <code>go</code> directives</h4>
|
||||
|
||||
<p><!-- golang.org/issue/44976 -->
|
||||
|
@ -387,7 +397,7 @@ func Foo() bool {
|
|||
registers instead of the stack. This work is enabled for Linux, MacOS, and
|
||||
Windows on the 64-bit x86 architecture (the <code>linux/amd64</code>,
|
||||
<code>darwin/amd64</code>, <code>windows/amd64</code> ports). For a
|
||||
representative set of Go packages and programs, benchmarking has shown
|
||||
representative set of Go packages and programs, benchmarking has shown
|
||||
performance improvements of about 5%, and a typical reduction in binary size
|
||||
of about 2%.
|
||||
</p>
|
||||
|
@ -441,6 +451,67 @@ func Foo() bool {
|
|||
<a href="/pkg/runtime/cgo#Handle">runtime/cgo.Handle</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="semicolons">URL query parsing</h3>
|
||||
<!-- CL 325697, CL 326309 -->
|
||||
|
||||
<p>
|
||||
The <code>net/url</code> and <code>net/http</code> packages used to accept
|
||||
<code>";"</code> (semicolon) as a setting separator in URL queries, in
|
||||
addition to <code>"&"</code> (ampersand). Now, settings with non-percent-encoded
|
||||
semicolons are rejected and <code>net/http</code> servers will log a warning to
|
||||
<a href="/pkg/net/http#Server.ErrorLog"><code>Server.ErrorLog</code></a>
|
||||
when encountering one in a request URL.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, before Go 1.17 the <a href="/pkg/net/url#URL.Query"><code>Query</code></a>
|
||||
method of the URL <code>example?a=1;b=2&c=3</code> would have returned
|
||||
<code>map[a:[1] b:[2] c:[3]]</code>, while now it returns <code>map[c:[3]]</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When encountering such a query string,
|
||||
<a href="/pkg/net/url#URL.Query"><code>URL.Query</code></a>
|
||||
and
|
||||
<a href="/pkg/net/http#Request.FormValue"><code>Request.FormValue</code></a>
|
||||
ignore any settings that contain a semicolon,
|
||||
<a href="/pkg/net/url#ParseQuery"><code>ParseQuery</code></a>
|
||||
returns the remaining settings and an error, and
|
||||
<a href="/pkg/net/http#Request.ParseForm"><code>Request.ParseForm</code></a>
|
||||
and
|
||||
<a href="/pkg/net/http#Request.ParseMultipartForm"><code>Request.ParseMultipartForm</code></a>
|
||||
return an error but still set <code>Request</code> fields based on the
|
||||
remaining settings.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>net/http</code> users can restore the original behavior by using the new
|
||||
<a href="/pkg/net/http#AllowQuerySemicolons"><code>AllowQuerySemicolons</code></a>
|
||||
handler wrapper. This will also suppress the <code>ErrorLog</code> warning.
|
||||
Note that accepting semicolons as query separators can lead to security issues
|
||||
if different systems interpret cache keys differently.
|
||||
See <a href="https://golang.org/issue/25192">issue 25192</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="ALPN">TLS strict ALPN</h3>
|
||||
<!-- CL 289209, CL 325432 -->
|
||||
|
||||
<p>
|
||||
When <a href="/pkg/crypto/tls#Config.NextProtos"><code>Config.NextProtos</code></a>
|
||||
is set, servers now enforce that there is an overlap between the configured
|
||||
protocols and the ALPN protocols advertised by the client, if any. If there is
|
||||
no mutually supported protocol, the connection is closed with the
|
||||
<code>no_application_protocol</code> alert, as required by RFC 7301. This
|
||||
helps mitigate <a href="https://alpaca-attack.com/">the ALPACA cross-protocol attack</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As an exception, when the value <code>"h2"</code> is included in the server's
|
||||
<code>Config.NextProtos</code>, HTTP/1.1 clients will be allowed to connect as
|
||||
if they didn't support ALPN.
|
||||
See <a href="https://golang.org/issue/46310">issue 46310</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
||||
|
||||
<p>
|
||||
|
@ -549,14 +620,6 @@ func Foo() bool {
|
|||
methods. Canceling the context after the handshake has finished has no effect.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 289209 -->
|
||||
When <a href="/pkg/crypto/tls#Config.NextProtos"><code>Config.NextProtos</code></a>
|
||||
is set, servers now enforce that there is an overlap between the
|
||||
configured protocols and the protocols advertised by the client, if any.
|
||||
If there is no overlap the connection is closed with the
|
||||
<code>no_application_protocol</code> alert, as required by RFC 7301.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 314609 -->
|
||||
Cipher suite ordering is now handled entirely by the
|
||||
<code>crypto/tls</code> package. Currently, cipher suites are sorted based
|
||||
|
@ -576,6 +639,15 @@ func Foo() bool {
|
|||
weakness</a>. They are still enabled by default but only as a last resort,
|
||||
thanks to the cipher suite ordering change above.
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/45428 -->
|
||||
Beginning in the next release, Go 1.18, the
|
||||
<a href="/pkg/crypto/tls/#Config.MinVersion"><code>Config.MinVersion</code></a>
|
||||
for <code>crypto/tls</code> clients will default to TLS 1.2, disabling TLS 1.0
|
||||
and TLS 1.1 by default. Applications will be able to override the change by
|
||||
explicitly setting <code>Config.MinVersion</code>.
|
||||
This will not affect <code>crypto/tls</code> servers.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/tls -->
|
||||
|
||||
|
@ -603,6 +675,14 @@ func Foo() bool {
|
|||
roots. This adds support for the new system trusted certificate store in
|
||||
FreeBSD 12.2+.
|
||||
</p>
|
||||
|
||||
<p><!-- golang.org/issue/41682 -->
|
||||
Beginning in the next release, Go 1.18, <code>crypto/x509</code> will
|
||||
reject certificates signed with the SHA-1 hash function. This doesn't
|
||||
apply to self-signed root certificates. Practical attacks against SHA-1
|
||||
<a href="https://shattered.io/">have been demonstrated in 2017</a> and publicly
|
||||
trusted Certificate Authorities have not issued SHA-1 certificates since 2015.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/x509 -->
|
||||
|
||||
|
@ -658,6 +738,22 @@ func Foo() bool {
|
|||
</dd>
|
||||
</dl><!-- encoding/csv -->
|
||||
|
||||
<dl id="encoding/xml"><dt><a href="/pkg/encoding/xml/">encoding/xml</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 277893 -->
|
||||
When a comment appears within a
|
||||
<a href="/pkg/encoding/xml/#Directive"><code>Directive</code></a>, it is now replaced
|
||||
with a single space instead of being completely elided.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Invalid element or attribute names with leading, trailing, or multiple
|
||||
colons are now stored unmodified into the
|
||||
<a href="/pkg/encoding/xml/#Name"><code>Name.Local</code></a> field.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- encoding/xml -->
|
||||
|
||||
<dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 271788 -->
|
||||
|
@ -693,6 +789,29 @@ func Foo() bool {
|
|||
</dd>
|
||||
</dl><!-- go/format -->
|
||||
|
||||
<dl id="go/parser"><dt><a href="/pkg/go/parser/">go/parser</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 306149 -->
|
||||
The new <a href="/pkg/go/parser/#SkipObjectResolution"><code>SkipObjectResolution</code></a>
|
||||
<code>Mode</code> value instructs the parser not to resolve identifiers to
|
||||
their declaration. This may improve parsing speed.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- go/parser -->
|
||||
|
||||
<dl id="image"><dt><a href="/pkg/image/">image</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 311129 -->
|
||||
The concrete image types (<code>RGBA</code>, <code>Gray16</code> and so on)
|
||||
now implement a new <a href="/pkg/image/#RGBA64Image"><code>RGBA64Image</code></a>
|
||||
interface. Those concrete types, other than the chroma-subsampling
|
||||
related <code>YCbCr</code> and <code>NYCbCrA</code>, also now implement
|
||||
<a href="/pkg/image/draw/#RGBA64Image"><code>draw.RGBA64Image</code></a>, a
|
||||
new interface in the <code>image/draw</code> package.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- image -->
|
||||
|
||||
<dl id="io/fs"><dt><a href="/pkg/io/fs/">io/fs</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 293649 -->
|
||||
|
@ -721,6 +840,20 @@ func Foo() bool {
|
|||
</dd>
|
||||
</dl><!-- mime -->
|
||||
|
||||
<dl id="mime/multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 313809 -->
|
||||
<a href="/pkg/mime/multipart/#Part.FileName"><code>Part.FileName</code></a>
|
||||
now applies
|
||||
<a href="/pkg/path/filepath/#Base"><code>filepath.Base</code></a> to the
|
||||
return value. This mitigates potential path traversal vulnerabilities in
|
||||
applications that accept multipart messages, such as <code>net/http</code>
|
||||
servers that call
|
||||
<a href="/pkg/net/http/#Request.FormFile"><code>Request.FormFile</code></a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- mime/multipart -->
|
||||
|
||||
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 272668 -->
|
||||
|
@ -740,7 +873,7 @@ func Foo() bool {
|
|||
the <a href="/pkg/net/#Error"><code>net.Error</code></a> interface.
|
||||
</p>
|
||||
|
||||
<p><!-- CL325829 -->
|
||||
<p><!-- CL 325829 -->
|
||||
The <a href="/pkg/net/#ParseIP"><code>ParseIP</code></a> and <a href="/pkg/net/#ParseCIDR"><code>ParseCIDR</code></a>
|
||||
functions now reject IPv4 addresses which contain decimal components with leading zeros.
|
||||
|
||||
|
@ -771,6 +904,29 @@ func Foo() bool {
|
|||
The <a href="/pkg/net/http/#ReadRequest"><code>ReadRequest</code></a> function
|
||||
now returns an error when the request has multiple Host headers.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 313950 -->
|
||||
When producing a redirect to the cleaned version of a URL,
|
||||
<a href="/pkg/net/http/#ServeMux"><code>ServeMux</code></a> now always
|
||||
uses relative URLs in the <code>Location</code> header. Previously it
|
||||
would echo the full URL of the request, which could lead to unintended
|
||||
redirects if the client could be made to send an absolute request URL.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 308009, CL 313489 -->
|
||||
When interpreting certain HTTP headers handled by <code>net/http</code>,
|
||||
non-ASCII characters are now ignored or rejected.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 325697 -->
|
||||
If
|
||||
<a href="/pkg/net/http/#Request.ParseForm"><code>Request.ParseForm</code></a>
|
||||
returns an error when called by
|
||||
<a href="/pkg/net/http/#Request.ParseMultipartForm"><code>Request.ParseMultipartForm</code></a>,
|
||||
the latter now continues populating
|
||||
<a href="/pkg/net/http/#Request.MultipartForm"><code>Request.MultipartForm</code></a>
|
||||
before returning it.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- net/http -->
|
||||
|
||||
|
|
|
@ -1003,7 +1003,8 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
|
|||
p.errorf("unimplemented two-register form")
|
||||
}
|
||||
a.Index = r1
|
||||
if scale != 0 && p.arch.Family == sys.ARM64 {
|
||||
if scale != 0 && scale != 1 && p.arch.Family == sys.ARM64 {
|
||||
// Support (R1)(R2) (no scaling) and (R1)(R2*1).
|
||||
p.errorf("arm64 doesn't support scaled register format")
|
||||
} else {
|
||||
a.Scale = int16(scale)
|
||||
|
|
2
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
2
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
|
@ -547,6 +547,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
|||
// shifted or extended register offset.
|
||||
MOVD (R2)(R6.SXTW), R4 // 44c866f8
|
||||
MOVD (R3)(R6), R5 // 656866f8
|
||||
MOVD (R3)(R6*1), R5 // 656866f8
|
||||
MOVD (R2)(R6), R4 // 446866f8
|
||||
MOVWU (R19)(R20<<2), R20 // 747a74b8
|
||||
MOVD (R2)(R6<<3), R4 // 447866f8
|
||||
|
@ -579,6 +580,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
|||
MOVB R4, (R2)(R6.SXTX) // 44e82638
|
||||
MOVB R8, (R3)(R9.UXTW) // 68482938
|
||||
MOVB R10, (R5)(R8) // aa682838
|
||||
MOVB R10, (R5)(R8*1) // aa682838
|
||||
MOVH R11, (R2)(R7.SXTW<<1) // 4bd82778
|
||||
MOVH R5, (R1)(R2<<1) // 25782278
|
||||
MOVH R7, (R2)(R5.SXTX<<1) // 47f82578
|
||||
|
|
|
@ -152,7 +152,7 @@ func lockVersion(mod module.Version) (unlock func(), err error) {
|
|||
// If err is nil, the caller MUST eventually call the unlock function.
|
||||
func SideLock() (unlock func(), err error) {
|
||||
if err := checkCacheDir(); err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
path := filepath.Join(cfg.GOMODCACHE, "cache", "lock")
|
||||
|
|
|
@ -1153,6 +1153,7 @@ func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPack
|
|||
Tags: imports.AnyTags(),
|
||||
VendorModulesInGOROOTSrc: true,
|
||||
LoadTests: *getT,
|
||||
AssumeRootsImported: true, // After 'go get foo', imports of foo should build.
|
||||
SilencePackageErrors: true, // May be fixed by subsequent upgrades or downgrades.
|
||||
}
|
||||
|
||||
|
|
|
@ -443,7 +443,7 @@ func expandGraph(ctx context.Context, rs *Requirements) (*Requirements, *ModuleG
|
|||
// roots — but in a lazy module it may pull in previously-irrelevant
|
||||
// transitive dependencies.
|
||||
|
||||
newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil, nil)
|
||||
newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil, nil, false)
|
||||
if rsErr != nil {
|
||||
// Failed to update roots, perhaps because of an error in a transitive
|
||||
// dependency needed for the update. Return the original Requirements
|
||||
|
@ -517,11 +517,11 @@ func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Require
|
|||
return tidyLazyRoots(ctx, rs.direct, pkgs)
|
||||
}
|
||||
|
||||
func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version) (*Requirements, error) {
|
||||
func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
|
||||
if rs.depth == eager {
|
||||
return updateEagerRoots(ctx, direct, rs, add)
|
||||
}
|
||||
return updateLazyRoots(ctx, direct, rs, pkgs, add)
|
||||
return updateLazyRoots(ctx, direct, rs, pkgs, add, rootsImported)
|
||||
}
|
||||
|
||||
// tidyLazyRoots returns a minimal set of root requirements that maintains the
|
||||
|
@ -661,7 +661,7 @@ func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg)
|
|||
//
|
||||
// (See https://golang.org/design/36460-lazy-module-loading#invariants for more
|
||||
// detail.)
|
||||
func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version) (*Requirements, error) {
|
||||
func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
|
||||
roots := rs.rootModules
|
||||
rootsUpgraded := false
|
||||
|
||||
|
@ -688,6 +688,10 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
|
|||
//
|
||||
// (This is the “import invariant” that makes lazy loading possible.)
|
||||
|
||||
case rootsImported && pkg.flags.has(pkgFromRoot):
|
||||
// pkg is a transitive dependency of some root, and we are treating the
|
||||
// roots as if they are imported by the main module (as in 'go get').
|
||||
|
||||
case pkg.flags.has(pkgIsRoot):
|
||||
// pkg is a root of the package-import graph. (Generally this means that
|
||||
// it matches a command-line argument.) We want future invocations of the
|
||||
|
|
|
@ -661,7 +661,7 @@ func requirementsFromModFile(ctx context.Context) *Requirements {
|
|||
for _, n := range mPathCount {
|
||||
if n > 1 {
|
||||
var err error
|
||||
rs, err = updateRoots(ctx, rs.direct, rs, nil, nil)
|
||||
rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
|
||||
if err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
}
|
||||
|
|
|
@ -171,6 +171,11 @@ type PackageOpts struct {
|
|||
// if the flag is set to "readonly" (the default) or "vendor".
|
||||
ResolveMissingImports bool
|
||||
|
||||
// AssumeRootsImported indicates that the transitive dependencies of the root
|
||||
// packages should be treated as if those roots will be imported by the main
|
||||
// module.
|
||||
AssumeRootsImported bool
|
||||
|
||||
// AllowPackage, if non-nil, is called after identifying the module providing
|
||||
// each package. If AllowPackage returns a non-nil error, that error is set
|
||||
// for the package, and the imports and test of that package will not be
|
||||
|
@ -875,6 +880,11 @@ const (
|
|||
// are also roots (and must be marked pkgIsRoot).
|
||||
pkgIsRoot
|
||||
|
||||
// pkgFromRoot indicates that the package is in the transitive closure of
|
||||
// imports starting at the roots. (Note that every package marked as pkgIsRoot
|
||||
// is also trivially marked pkgFromRoot.)
|
||||
pkgFromRoot
|
||||
|
||||
// pkgImportsLoaded indicates that the imports and testImports fields of a
|
||||
// loadPkg have been populated.
|
||||
pkgImportsLoaded
|
||||
|
@ -1068,7 +1078,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
|
|||
// iteration so we don't need to also update it here. (That would waste time
|
||||
// computing a "direct" map that we'll have to recompute later anyway.)
|
||||
direct := ld.requirements.direct
|
||||
rs, err := updateRoots(ctx, direct, ld.requirements, noPkgs, toAdd)
|
||||
rs, err := updateRoots(ctx, direct, ld.requirements, noPkgs, toAdd, ld.AssumeRootsImported)
|
||||
if err != nil {
|
||||
// If an error was found in a newly added module, report the package
|
||||
// import stack instead of the module requirement stack. Packages
|
||||
|
@ -1274,7 +1284,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
|
|||
addRoots = tidy.rootModules
|
||||
}
|
||||
|
||||
rs, err = updateRoots(ctx, direct, rs, ld.pkgs, addRoots)
|
||||
rs, err = updateRoots(ctx, direct, rs, ld.pkgs, addRoots, ld.AssumeRootsImported)
|
||||
if err != nil {
|
||||
// We don't actually know what even the root requirements are supposed to be,
|
||||
// so we can't proceed with loading. Return the error to the caller
|
||||
|
@ -1433,6 +1443,9 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
|
|||
// This package matches a root pattern by virtue of being in "all".
|
||||
flags |= pkgIsRoot
|
||||
}
|
||||
if flags.has(pkgIsRoot) {
|
||||
flags |= pkgFromRoot
|
||||
}
|
||||
|
||||
old := pkg.flags.update(flags)
|
||||
new := old | flags
|
||||
|
@ -1487,6 +1500,12 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
|
|||
ld.applyPkgFlags(ctx, dep, pkgInAll)
|
||||
}
|
||||
}
|
||||
|
||||
if new.has(pkgFromRoot) && !old.has(pkgFromRoot|pkgImportsLoaded) {
|
||||
for _, dep := range pkg.imports {
|
||||
ld.applyPkgFlags(ctx, dep, pkgFromRoot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// preloadRootModules loads the module requirements needed to identify the
|
||||
|
@ -1549,7 +1568,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
|
|||
}
|
||||
module.Sort(toAdd)
|
||||
|
||||
rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd)
|
||||
rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd, ld.AssumeRootsImported)
|
||||
if err != nil {
|
||||
// We are missing some root dependency, and for some reason we can't load
|
||||
// enough of the module dependency graph to add the missing root. Package
|
||||
|
|
15
src/cmd/go/testdata/script/mod_edit_no_modcache.txt
vendored
Normal file
15
src/cmd/go/testdata/script/mod_edit_no_modcache.txt
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
# 'go mod edit' opportunistically locks the side-lock file in the module cache,
|
||||
# for compatibility with older versions of the 'go' command.
|
||||
# It does not otherwise depend on the module cache, so it should not
|
||||
# fail if the module cache directory cannot be created.
|
||||
|
||||
[root] skip
|
||||
|
||||
mkdir $WORK/readonly
|
||||
chmod 0555 $WORK/readonly
|
||||
env GOPATH=$WORK/readonly/nonexist
|
||||
|
||||
go mod edit -go=1.17
|
||||
|
||||
-- go.mod --
|
||||
module example.com/m
|
44
src/cmd/go/testdata/script/mod_get_lazy_indirect.txt
vendored
Normal file
44
src/cmd/go/testdata/script/mod_get_lazy_indirect.txt
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
# https://golang.org/issue/45979: after 'go get' on a package,
|
||||
# that package should be importable without error.
|
||||
|
||||
|
||||
# We start out with an unresolved dependency.
|
||||
# 'go list' suggests that we run 'go get' on that dependency.
|
||||
|
||||
! go list -deps .
|
||||
stderr '^m.go:3:8: no required module provides package rsc\.io/quote; to add it:\n\tgo get rsc.io/quote$'
|
||||
|
||||
|
||||
# When we run the suggested 'go get' command, the new dependency can be used
|
||||
# immediately.
|
||||
#
|
||||
# 'go get' marks the new dependency as 'indirect', because it doesn't scan
|
||||
# enough source code to know whether it is direct, and it is easier and less
|
||||
# invasive to remove an incorrect indirect mark (e.g. using 'go get') than to
|
||||
# add one that is missing ('go mod tidy' or 'go mod vendor').
|
||||
|
||||
go get rsc.io/quote
|
||||
grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod
|
||||
! grep 'rsc.io/quote v\d+\.\d+\.\d+$' go.mod
|
||||
|
||||
go list -deps .
|
||||
! stderr .
|
||||
[!short] go build .
|
||||
[!short] ! stderr .
|
||||
|
||||
|
||||
# 'go get .' (or 'go mod tidy') removes the indirect mark.
|
||||
|
||||
go get .
|
||||
grep 'rsc.io/quote v\d+\.\d+\.\d+$' go.mod
|
||||
! grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod
|
||||
|
||||
|
||||
-- go.mod --
|
||||
module example.com/m
|
||||
|
||||
go 1.17
|
||||
-- m.go --
|
||||
package m
|
||||
|
||||
import _ "rsc.io/quote"
|
36
src/cmd/go/testdata/script/mod_sumdb_golang.txt
vendored
36
src/cmd/go/testdata/script/mod_sumdb_golang.txt
vendored
|
@ -10,45 +10,73 @@ go env GOSUMDB
|
|||
stdout '^sum.golang.org$'
|
||||
|
||||
# Download direct from github.
|
||||
|
||||
[!net] skip
|
||||
[!exec:git] skip
|
||||
env GOSUMDB=sum.golang.org
|
||||
env GOPROXY=direct
|
||||
|
||||
go get -d rsc.io/quote@v1.5.2
|
||||
cp go.sum saved.sum
|
||||
|
||||
|
||||
# Download from proxy.golang.org with go.sum entry already.
|
||||
# Use 'go list' instead of 'go get' since the latter may download extra go.mod
|
||||
# files not listed in go.sum.
|
||||
|
||||
go clean -modcache
|
||||
env GOSUMDB=
|
||||
env GOPROXY=
|
||||
go list -x -deps rsc.io/quote
|
||||
|
||||
go list -x -m all # Download go.mod files.
|
||||
! stderr github
|
||||
stderr proxy.golang.org/rsc.io/quote
|
||||
! stderr sum.golang.org/tile
|
||||
! stderr sum.golang.org/lookup/rsc.io/quote
|
||||
|
||||
go list -x -deps rsc.io/quote # Download module source.
|
||||
! stderr github
|
||||
stderr proxy.golang.org/rsc.io/quote
|
||||
! stderr sum.golang.org/tile
|
||||
! stderr sum.golang.org/lookup/rsc.io/quote
|
||||
|
||||
cmp go.sum saved.sum
|
||||
|
||||
|
||||
# Download again.
|
||||
# Should use the checksum database to validate new go.sum lines,
|
||||
# but not need to fetch any new data from the proxy.
|
||||
|
||||
rm go.sum
|
||||
go list -mod=mod -x rsc.io/quote
|
||||
|
||||
go list -mod=mod -x -m all # Add checksums for go.mod files.
|
||||
stderr sum.golang.org/tile
|
||||
! stderr github
|
||||
! stderr proxy.golang.org/rsc.io/quote
|
||||
stderr sum.golang.org/tile
|
||||
stderr sum.golang.org/lookup/rsc.io/quote
|
||||
|
||||
go list -mod=mod -x rsc.io/quote # Add checksums for module source.
|
||||
! stderr . # Adds checksums, but for entities already in the module cache.
|
||||
|
||||
cmp go.sum saved.sum
|
||||
|
||||
|
||||
# test fallback to direct
|
||||
|
||||
env TESTGOPROXY404=1
|
||||
go clean -modcache
|
||||
rm go.sum
|
||||
go list -mod=mod -x rsc.io/quote
|
||||
|
||||
go list -mod=mod -x -m all # Download go.mod files
|
||||
stderr 'proxy.golang.org.*404 testing'
|
||||
stderr github.com/rsc
|
||||
|
||||
go list -mod=mod -x rsc.io/quote # Download module source.
|
||||
stderr 'proxy.golang.org.*404 testing'
|
||||
stderr github.com/rsc
|
||||
|
||||
cmp go.sum saved.sum
|
||||
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
|
|
@ -233,8 +233,8 @@ func (f *file) Name() string {
|
|||
}
|
||||
|
||||
func (f *file) ObjAddr(addr uint64) (uint64, error) {
|
||||
// No support for shared libraries.
|
||||
return 0, nil
|
||||
// No support for shared libraries, so translation is a no-op.
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
func (f *file) BuildID() string {
|
||||
|
|
127
src/cmd/pprof/pprof_test.go
Normal file
127
src/cmd/pprof/pprof_test.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var tmp, pprofExe string // populated by buildPprof
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
if !testenv.HasGoBuild() {
|
||||
return
|
||||
}
|
||||
|
||||
var exitcode int
|
||||
if err := buildPprof(); err == nil {
|
||||
exitcode = m.Run()
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
exitcode = 1
|
||||
}
|
||||
os.RemoveAll(tmp)
|
||||
os.Exit(exitcode)
|
||||
}
|
||||
|
||||
func buildPprof() error {
|
||||
var err error
|
||||
tmp, err = os.MkdirTemp("", "TestPprof")
|
||||
if err != nil {
|
||||
return fmt.Errorf("TempDir failed: %v", err)
|
||||
}
|
||||
|
||||
pprofExe = filepath.Join(tmp, "testpprof.exe")
|
||||
gotool, err := testenv.GoTool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err := exec.Command(gotool, "build", "-o", pprofExe, "cmd/pprof").CombinedOutput()
|
||||
if err != nil {
|
||||
os.RemoveAll(tmp)
|
||||
return fmt.Errorf("go build -o %v cmd/pprof: %v\n%s", pprofExe, err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// See also runtime/pprof.cpuProfilingBroken.
|
||||
func mustHaveCPUProfiling(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "plan9":
|
||||
t.Skipf("skipping on %s, unimplemented", runtime.GOOS)
|
||||
case "aix":
|
||||
t.Skipf("skipping on %s, issue 45170", runtime.GOOS)
|
||||
case "ios", "dragonfly", "netbsd", "illumos", "solaris":
|
||||
t.Skipf("skipping on %s, issue 13841", runtime.GOOS)
|
||||
case "openbsd":
|
||||
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
|
||||
t.Skipf("skipping on %s/%s, issue 13841", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mustHaveDisasm(t *testing.T) {
|
||||
switch runtime.GOARCH {
|
||||
case "mips", "mipsle", "mips64", "mips64le":
|
||||
t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
|
||||
case "riscv64":
|
||||
t.Skipf("skipping on %s, issue 36738", runtime.GOARCH)
|
||||
case "s390x":
|
||||
t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
|
||||
}
|
||||
|
||||
// Skip PIE platforms, pprof can't disassemble PIE.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("skipping on %s, issue 46639", runtime.GOOS)
|
||||
}
|
||||
if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
|
||||
t.Skipf("skipping on %s/%s, issue 46639", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDisasm verifies that cmd/pprof can successfully disassemble functions.
|
||||
//
|
||||
// This is a regression test for issue 46636.
|
||||
func TestDisasm(t *testing.T) {
|
||||
mustHaveCPUProfiling(t)
|
||||
mustHaveDisasm(t)
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
tmpdir := t.TempDir()
|
||||
cpuExe := filepath.Join(tmpdir, "cpu.exe")
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", cpuExe, "cpu.go")
|
||||
cmd.Dir = "testdata/"
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("build failed: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
profile := filepath.Join(tmpdir, "cpu.pprof")
|
||||
cmd = exec.Command(cpuExe, "-output", profile)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("cpu failed: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
cmd = exec.Command(pprofExe, "-disasm", "main.main", cpuExe, profile)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("pprof failed: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
sout := string(out)
|
||||
want := "ROUTINE ======================== main.main"
|
||||
if !strings.Contains(sout, want) {
|
||||
t.Errorf("pprof disasm got %s want contains %q", sout, want)
|
||||
}
|
||||
}
|
41
src/cmd/pprof/testdata/cpu.go
vendored
Normal file
41
src/cmd/pprof/testdata/cpu.go
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
)
|
||||
|
||||
var output = flag.String("output", "", "pprof profile output file")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if *output == "" {
|
||||
fmt.Fprintf(os.Stderr, "usage: %s -output file.pprof\n", os.Args[0])
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
f, err := os.Create(*output)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
|
||||
// Spin for long enough to collect some samples.
|
||||
start := time.Now()
|
||||
for time.Since(start) < time.Second {
|
||||
}
|
||||
}
|
|
@ -2838,9 +2838,10 @@ func TestTxStmtDeadlock(t *testing.T) {
|
|||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,16 @@ type Image interface {
|
|||
Set(x, y int, c color.Color)
|
||||
}
|
||||
|
||||
// RGBA64Image extends both the Image and image.RGBA64Image interfaces with a
|
||||
// SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to
|
||||
// calling Set, but it can avoid allocations from converting concrete color
|
||||
// types to the color.Color interface type.
|
||||
type RGBA64Image interface {
|
||||
image.RGBA64Image
|
||||
Set(x, y int, c color.Color)
|
||||
SetRGBA64(x, y int, c color.RGBA64)
|
||||
}
|
||||
|
||||
// Quantizer produces a palette for an image.
|
||||
type Quantizer interface {
|
||||
// Quantize appends up to cap(p) - len(p) colors to p and returns the
|
||||
|
|
|
@ -45,6 +45,17 @@ type Image interface {
|
|||
At(x, y int) color.Color
|
||||
}
|
||||
|
||||
// RGBA64Image is an Image whose pixels can be converted directly to a
|
||||
// color.RGBA64.
|
||||
type RGBA64Image interface {
|
||||
// RGBA64At returns the RGBA64 color of the pixel at (x, y). It is
|
||||
// equivalent to calling At(x, y).RGBA() and converting the resulting
|
||||
// 32-bit return values to a color.RGBA64, but it can avoid allocations
|
||||
// from converting concrete color types to the color.Color interface type.
|
||||
RGBA64At(x, y int) color.RGBA64
|
||||
Image
|
||||
}
|
||||
|
||||
// PalettedImage is an image whose colors may come from a limited palette.
|
||||
// If m is a PalettedImage and m.ColorModel() returns a color.Palette p,
|
||||
// then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
|
||||
|
@ -90,6 +101,24 @@ func (p *RGBA) At(x, y int) color.Color {
|
|||
return p.RGBAAt(x, y)
|
||||
}
|
||||
|
||||
func (p *RGBA) RGBA64At(x, y int) color.RGBA64 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.RGBA64{}
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
r := uint16(s[0])
|
||||
g := uint16(s[1])
|
||||
b := uint16(s[2])
|
||||
a := uint16(s[3])
|
||||
return color.RGBA64{
|
||||
(r << 8) | r,
|
||||
(g << 8) | g,
|
||||
(b << 8) | b,
|
||||
(a << 8) | a,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *RGBA) RGBAAt(x, y int) color.RGBA {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.RGBA{}
|
||||
|
@ -118,6 +147,18 @@ func (p *RGBA) Set(x, y int, c color.Color) {
|
|||
s[3] = c1.A
|
||||
}
|
||||
|
||||
func (p *RGBA) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
s[0] = uint8(c.R >> 8)
|
||||
s[1] = uint8(c.G >> 8)
|
||||
s[2] = uint8(c.B >> 8)
|
||||
s[3] = uint8(c.A >> 8)
|
||||
}
|
||||
|
||||
func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
|
@ -311,6 +352,11 @@ func (p *NRGBA) At(x, y int) color.Color {
|
|||
return p.NRGBAAt(x, y)
|
||||
}
|
||||
|
||||
func (p *NRGBA) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.NRGBAAt(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.NRGBA{}
|
||||
|
@ -339,6 +385,24 @@ func (p *NRGBA) Set(x, y int, c color.Color) {
|
|||
s[3] = c1.A
|
||||
}
|
||||
|
||||
func (p *NRGBA) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
|
||||
if (a != 0) && (a != 0xffff) {
|
||||
r = (r * 0xffff) / a
|
||||
g = (g * 0xffff) / a
|
||||
b = (b * 0xffff) / a
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
s[0] = uint8(r >> 8)
|
||||
s[1] = uint8(g >> 8)
|
||||
s[2] = uint8(b >> 8)
|
||||
s[3] = uint8(a >> 8)
|
||||
}
|
||||
|
||||
func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
|
@ -415,6 +479,11 @@ func (p *NRGBA64) At(x, y int) color.Color {
|
|||
return p.NRGBA64At(x, y)
|
||||
}
|
||||
|
||||
func (p *NRGBA64) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.NRGBA64At(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.NRGBA64{}
|
||||
|
@ -452,6 +521,28 @@ func (p *NRGBA64) Set(x, y int, c color.Color) {
|
|||
s[7] = uint8(c1.A)
|
||||
}
|
||||
|
||||
func (p *NRGBA64) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
|
||||
if (a != 0) && (a != 0xffff) {
|
||||
r = (r * 0xffff) / a
|
||||
g = (g * 0xffff) / a
|
||||
b = (b * 0xffff) / a
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
s[0] = uint8(r >> 8)
|
||||
s[1] = uint8(r)
|
||||
s[2] = uint8(g >> 8)
|
||||
s[3] = uint8(g)
|
||||
s[4] = uint8(b >> 8)
|
||||
s[5] = uint8(b)
|
||||
s[6] = uint8(a >> 8)
|
||||
s[7] = uint8(a)
|
||||
}
|
||||
|
||||
func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
|
@ -532,6 +623,12 @@ func (p *Alpha) At(x, y int) color.Color {
|
|||
return p.AlphaAt(x, y)
|
||||
}
|
||||
|
||||
func (p *Alpha) RGBA64At(x, y int) color.RGBA64 {
|
||||
a := uint16(p.AlphaAt(x, y).A)
|
||||
a |= a << 8
|
||||
return color.RGBA64{a, a, a, a}
|
||||
}
|
||||
|
||||
func (p *Alpha) AlphaAt(x, y int) color.Alpha {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.Alpha{}
|
||||
|
@ -554,6 +651,14 @@ func (p *Alpha) Set(x, y int, c color.Color) {
|
|||
p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
|
||||
}
|
||||
|
||||
func (p *Alpha) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i] = uint8(c.A >> 8)
|
||||
}
|
||||
|
||||
func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
|
@ -626,6 +731,11 @@ func (p *Alpha16) At(x, y int) color.Color {
|
|||
return p.Alpha16At(x, y)
|
||||
}
|
||||
|
||||
func (p *Alpha16) RGBA64At(x, y int) color.RGBA64 {
|
||||
a := p.Alpha16At(x, y).A
|
||||
return color.RGBA64{a, a, a, a}
|
||||
}
|
||||
|
||||
func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.Alpha16{}
|
||||
|
@ -650,6 +760,15 @@ func (p *Alpha16) Set(x, y int, c color.Color) {
|
|||
p.Pix[i+1] = uint8(c1.A)
|
||||
}
|
||||
|
||||
func (p *Alpha16) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i+0] = uint8(c.A >> 8)
|
||||
p.Pix[i+1] = uint8(c.A)
|
||||
}
|
||||
|
||||
func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
|
@ -723,6 +842,12 @@ func (p *Gray) At(x, y int) color.Color {
|
|||
return p.GrayAt(x, y)
|
||||
}
|
||||
|
||||
func (p *Gray) RGBA64At(x, y int) color.RGBA64 {
|
||||
gray := uint16(p.GrayAt(x, y).Y)
|
||||
gray |= gray << 8
|
||||
return color.RGBA64{gray, gray, gray, 0xffff}
|
||||
}
|
||||
|
||||
func (p *Gray) GrayAt(x, y int) color.Gray {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.Gray{}
|
||||
|
@ -745,6 +870,16 @@ func (p *Gray) Set(x, y int, c color.Color) {
|
|||
p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
|
||||
}
|
||||
|
||||
func (p *Gray) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
// This formula is the same as in color.grayModel.
|
||||
gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 24
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i] = uint8(gray)
|
||||
}
|
||||
|
||||
func (p *Gray) SetGray(x, y int, c color.Gray) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
|
@ -804,6 +939,11 @@ func (p *Gray16) At(x, y int) color.Color {
|
|||
return p.Gray16At(x, y)
|
||||
}
|
||||
|
||||
func (p *Gray16) RGBA64At(x, y int) color.RGBA64 {
|
||||
gray := p.Gray16At(x, y).Y
|
||||
return color.RGBA64{gray, gray, gray, 0xffff}
|
||||
}
|
||||
|
||||
func (p *Gray16) Gray16At(x, y int) color.Gray16 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.Gray16{}
|
||||
|
@ -828,6 +968,17 @@ func (p *Gray16) Set(x, y int, c color.Color) {
|
|||
p.Pix[i+1] = uint8(c1.Y)
|
||||
}
|
||||
|
||||
func (p *Gray16) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
// This formula is the same as in color.gray16Model.
|
||||
gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 16
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i+0] = uint8(gray >> 8)
|
||||
p.Pix[i+1] = uint8(gray)
|
||||
}
|
||||
|
||||
func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
|
@ -888,6 +1039,11 @@ func (p *CMYK) At(x, y int) color.Color {
|
|||
return p.CMYKAt(x, y)
|
||||
}
|
||||
|
||||
func (p *CMYK) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.CMYKAt(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *CMYK) CMYKAt(x, y int) color.CMYK {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.CMYK{}
|
||||
|
@ -916,6 +1072,19 @@ func (p *CMYK) Set(x, y int, c color.Color) {
|
|||
s[3] = c1.K
|
||||
}
|
||||
|
||||
func (p *CMYK) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
cc, mm, yy, kk := color.RGBToCMYK(uint8(c.R>>8), uint8(c.G>>8), uint8(c.B>>8))
|
||||
i := p.PixOffset(x, y)
|
||||
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
s[0] = cc
|
||||
s[1] = mm
|
||||
s[2] = yy
|
||||
s[3] = kk
|
||||
}
|
||||
|
||||
func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
|
@ -988,6 +1157,26 @@ func (p *Paletted) At(x, y int) color.Color {
|
|||
return p.Palette[p.Pix[i]]
|
||||
}
|
||||
|
||||
func (p *Paletted) RGBA64At(x, y int) color.RGBA64 {
|
||||
if len(p.Palette) == 0 {
|
||||
return color.RGBA64{}
|
||||
}
|
||||
c := color.Color(nil)
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
c = p.Palette[0]
|
||||
} else {
|
||||
i := p.PixOffset(x, y)
|
||||
c = p.Palette[p.Pix[i]]
|
||||
}
|
||||
r, g, b, a := c.RGBA()
|
||||
return color.RGBA64{
|
||||
uint16(r),
|
||||
uint16(g),
|
||||
uint16(b),
|
||||
uint16(a),
|
||||
}
|
||||
}
|
||||
|
||||
// PixOffset returns the index of the first element of Pix that corresponds to
|
||||
// the pixel at (x, y).
|
||||
func (p *Paletted) PixOffset(x, y int) int {
|
||||
|
@ -1002,6 +1191,14 @@ func (p *Paletted) Set(x, y int, c color.Color) {
|
|||
p.Pix[i] = uint8(p.Palette.Index(c))
|
||||
}
|
||||
|
||||
func (p *Paletted) SetRGBA64(x, y int, c color.RGBA64) {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return
|
||||
}
|
||||
i := p.PixOffset(x, y)
|
||||
p.Pix[i] = uint8(p.Palette.Index(c))
|
||||
}
|
||||
|
||||
func (p *Paletted) ColorIndexAt(x, y int) uint8 {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return 0
|
||||
|
|
|
@ -6,6 +6,7 @@ package image
|
|||
|
||||
import (
|
||||
"image/color"
|
||||
"image/color/palette"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -191,6 +192,80 @@ func Test16BitsPerColorChannel(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRGBA64Image(t *testing.T) {
|
||||
// memset sets every element of s to v.
|
||||
memset := func(s []byte, v byte) {
|
||||
for i := range s {
|
||||
s[i] = v
|
||||
}
|
||||
}
|
||||
|
||||
r := Rect(0, 0, 3, 2)
|
||||
testCases := []Image{
|
||||
NewAlpha(r),
|
||||
NewAlpha16(r),
|
||||
NewCMYK(r),
|
||||
NewGray(r),
|
||||
NewGray16(r),
|
||||
NewNRGBA(r),
|
||||
NewNRGBA64(r),
|
||||
NewNYCbCrA(r, YCbCrSubsampleRatio444),
|
||||
NewPaletted(r, palette.Plan9),
|
||||
NewRGBA(r),
|
||||
NewRGBA64(r),
|
||||
NewYCbCr(r, YCbCrSubsampleRatio444),
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
switch tc := tc.(type) {
|
||||
// Most of the concrete image types in the testCases implement the
|
||||
// draw.RGBA64Image interface: they have a SetRGBA64 method. We use an
|
||||
// interface literal here, instead of importing "image/draw", to avoid
|
||||
// an import cycle.
|
||||
//
|
||||
// The YCbCr and NYCbCrA types are special-cased. Chroma subsampling
|
||||
// means that setting one pixel can modify neighboring pixels. They
|
||||
// don't have Set or SetRGBA64 methods because that side effect could
|
||||
// be surprising. Here, we just memset the channel buffers instead.
|
||||
case interface {
|
||||
SetRGBA64(x, y int, c color.RGBA64)
|
||||
}:
|
||||
tc.SetRGBA64(1, 1, color.RGBA64{0x7FFF, 0x3FFF, 0x0000, 0x7FFF})
|
||||
|
||||
case *NYCbCrA:
|
||||
memset(tc.YCbCr.Y, 0x77)
|
||||
memset(tc.YCbCr.Cb, 0x88)
|
||||
memset(tc.YCbCr.Cr, 0x99)
|
||||
memset(tc.A, 0xAA)
|
||||
|
||||
case *YCbCr:
|
||||
memset(tc.Y, 0x77)
|
||||
memset(tc.Cb, 0x88)
|
||||
memset(tc.Cr, 0x99)
|
||||
|
||||
default:
|
||||
t.Errorf("could not initialize pixels for %T", tc)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check that RGBA64At(x, y) is equivalent to At(x, y).RGBA().
|
||||
rgba64Image, ok := tc.(RGBA64Image)
|
||||
if !ok {
|
||||
t.Errorf("%T is not an RGBA64Image", tc)
|
||||
continue
|
||||
}
|
||||
got := rgba64Image.RGBA64At(1, 1)
|
||||
wantR, wantG, wantB, wantA := tc.At(1, 1).RGBA()
|
||||
if (uint32(got.R) != wantR) || (uint32(got.G) != wantG) ||
|
||||
(uint32(got.B) != wantB) || (uint32(got.A) != wantA) {
|
||||
t.Errorf("%T:\ngot (0x%04X, 0x%04X, 0x%04X, 0x%04X)\n"+
|
||||
"want (0x%04X, 0x%04X, 0x%04X, 0x%04X)", tc,
|
||||
got.R, got.G, got.B, got.A,
|
||||
wantR, wantG, wantB, wantA)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAt(b *testing.B) {
|
||||
for _, tc := range testImages {
|
||||
b.Run(tc.name, func(b *testing.B) {
|
||||
|
|
|
@ -71,6 +71,11 @@ func (p *YCbCr) At(x, y int) color.Color {
|
|||
return p.YCbCrAt(x, y)
|
||||
}
|
||||
|
||||
func (p *YCbCr) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.YCbCrAt(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.YCbCr{}
|
||||
|
@ -210,6 +215,11 @@ func (p *NYCbCrA) At(x, y int) color.Color {
|
|||
return p.NYCbCrAAt(x, y)
|
||||
}
|
||||
|
||||
func (p *NYCbCrA) RGBA64At(x, y int) color.RGBA64 {
|
||||
r, g, b, a := p.NYCbCrAAt(x, y).RGBA()
|
||||
return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
|
||||
}
|
||||
|
||||
func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
|
||||
if !(Point{X: x, Y: y}.In(p.Rect)) {
|
||||
return color.NYCbCrA{}
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
// The default Source is safe for concurrent use by multiple goroutines, but
|
||||
// Sources created by NewSource are not.
|
||||
//
|
||||
// Mathematical interval notation such as [0, n) is used throughout the
|
||||
// documentation for this package.
|
||||
//
|
||||
// This package's outputs might be easily predictable regardless of how it's
|
||||
// seeded. For random numbers suitable for security-sensitive work, see the
|
||||
// crypto/rand package.
|
||||
|
@ -106,7 +103,7 @@ func (r *Rand) Int() int {
|
|||
return int(u << 1 >> 1) // clear sign bit if int == int32
|
||||
}
|
||||
|
||||
// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
|
||||
// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n).
|
||||
// It panics if n <= 0.
|
||||
func (r *Rand) Int63n(n int64) int64 {
|
||||
if n <= 0 {
|
||||
|
@ -123,7 +120,7 @@ func (r *Rand) Int63n(n int64) int64 {
|
|||
return v % n
|
||||
}
|
||||
|
||||
// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
|
||||
// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
|
||||
// It panics if n <= 0.
|
||||
func (r *Rand) Int31n(n int32) int32 {
|
||||
if n <= 0 {
|
||||
|
@ -140,7 +137,7 @@ func (r *Rand) Int31n(n int32) int32 {
|
|||
return v % n
|
||||
}
|
||||
|
||||
// int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
|
||||
// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
|
||||
// n must be > 0, but int31n does not check this; the caller must ensure it.
|
||||
// int31n exists because Int31n is inefficient, but Go 1 compatibility
|
||||
// requires that the stream of values produced by math/rand remain unchanged.
|
||||
|
@ -164,7 +161,7 @@ func (r *Rand) int31n(n int32) int32 {
|
|||
return int32(prod >> 32)
|
||||
}
|
||||
|
||||
// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
|
||||
// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n).
|
||||
// It panics if n <= 0.
|
||||
func (r *Rand) Intn(n int) int {
|
||||
if n <= 0 {
|
||||
|
@ -176,7 +173,7 @@ func (r *Rand) Intn(n int) int {
|
|||
return int(r.Int63n(int64(n)))
|
||||
}
|
||||
|
||||
// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
|
||||
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0).
|
||||
func (r *Rand) Float64() float64 {
|
||||
// A clearer, simpler implementation would be:
|
||||
// return float64(r.Int63n(1<<53)) / (1<<53)
|
||||
|
@ -202,7 +199,7 @@ again:
|
|||
return f
|
||||
}
|
||||
|
||||
// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
|
||||
// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0).
|
||||
func (r *Rand) Float32() float32 {
|
||||
// Same rationale as in Float64: we want to preserve the Go 1 value
|
||||
// stream except we want to fix it not to return 1.0
|
||||
|
@ -215,7 +212,8 @@ again:
|
|||
return f
|
||||
}
|
||||
|
||||
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
|
||||
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
|
||||
// in the half-open interval [0,n).
|
||||
func (r *Rand) Perm(n int) []int {
|
||||
m := make([]int, n)
|
||||
// In the following loop, the iteration when i=0 always swaps m[0] with m[0].
|
||||
|
@ -323,31 +321,31 @@ func Int31() int32 { return globalRand.Int31() }
|
|||
// Int returns a non-negative pseudo-random int from the default Source.
|
||||
func Int() int { return globalRand.Int() }
|
||||
|
||||
// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n)
|
||||
// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n)
|
||||
// from the default Source.
|
||||
// It panics if n <= 0.
|
||||
func Int63n(n int64) int64 { return globalRand.Int63n(n) }
|
||||
|
||||
// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n)
|
||||
// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n)
|
||||
// from the default Source.
|
||||
// It panics if n <= 0.
|
||||
func Int31n(n int32) int32 { return globalRand.Int31n(n) }
|
||||
|
||||
// Intn returns, as an int, a non-negative pseudo-random number in [0,n)
|
||||
// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n)
|
||||
// from the default Source.
|
||||
// It panics if n <= 0.
|
||||
func Intn(n int) int { return globalRand.Intn(n) }
|
||||
|
||||
// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0)
|
||||
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0)
|
||||
// from the default Source.
|
||||
func Float64() float64 { return globalRand.Float64() }
|
||||
|
||||
// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0)
|
||||
// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0)
|
||||
// from the default Source.
|
||||
func Float32() float32 { return globalRand.Float32() }
|
||||
|
||||
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n)
|
||||
// from the default Source.
|
||||
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
|
||||
// in the half-open interval [0,n) from the default Source.
|
||||
func Perm(n int) []int { return globalRand.Perm(n) }
|
||||
|
||||
// Shuffle pseudo-randomizes the order of elements using the default Source.
|
||||
|
|
|
@ -32,6 +32,11 @@ import (
|
|||
// The current value is set based on flakes observed in the Go builders.
|
||||
var settleTime = 100 * time.Millisecond
|
||||
|
||||
// fatalWaitingTime is an absurdly long time to wait for signals to be
|
||||
// delivered but, using it, we (hopefully) eliminate test flakes on the
|
||||
// build servers. See #46736 for discussion.
|
||||
var fatalWaitingTime = 30 * time.Second
|
||||
|
||||
func init() {
|
||||
if testenv.Builder() == "solaris-amd64-oraclerel" {
|
||||
// The solaris-amd64-oraclerel builder has been observed to time out in
|
||||
|
@ -84,7 +89,7 @@ func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) {
|
|||
// General user code should filter out all unexpected signals instead of just
|
||||
// SIGURG, but since os/signal is tightly coupled to the runtime it seems
|
||||
// appropriate to be stricter here.
|
||||
for time.Since(start) < settleTime {
|
||||
for time.Since(start) < fatalWaitingTime {
|
||||
select {
|
||||
case s := <-c:
|
||||
if s == sig {
|
||||
|
@ -97,7 +102,7 @@ func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) {
|
|||
timer.Reset(settleTime / 10)
|
||||
}
|
||||
}
|
||||
t.Fatalf("timeout after %v waiting for %v", settleTime, sig)
|
||||
t.Fatalf("timeout after %v waiting for %v", fatalWaitingTime, sig)
|
||||
}
|
||||
|
||||
// quiesce waits until we can be reasonably confident that all pending signals
|
||||
|
|
|
@ -12,12 +12,15 @@ import (
|
|||
|
||||
func ExampleFrames() {
|
||||
c := func() {
|
||||
// Ask runtime.Callers for up to 10 pcs, including runtime.Callers itself.
|
||||
// Ask runtime.Callers for up to 10 PCs, including runtime.Callers itself.
|
||||
pc := make([]uintptr, 10)
|
||||
n := runtime.Callers(0, pc)
|
||||
if n == 0 {
|
||||
// No pcs available. Stop now.
|
||||
// This can happen if the first argument to runtime.Callers is large.
|
||||
// No PCs available. This can happen if the first argument to
|
||||
// runtime.Callers is large.
|
||||
//
|
||||
// Return now to avoid processing the zero Frame that would
|
||||
// otherwise be returned by frames.Next below.
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -25,9 +28,12 @@ func ExampleFrames() {
|
|||
frames := runtime.CallersFrames(pc)
|
||||
|
||||
// Loop to get frames.
|
||||
// A fixed number of pcs can expand to an indefinite number of Frames.
|
||||
// A fixed number of PCs can expand to an indefinite number of Frames.
|
||||
for {
|
||||
frame, more := frames.Next()
|
||||
|
||||
// Process this frame.
|
||||
//
|
||||
// To keep this example's output stable
|
||||
// even if there are changes in the testing package,
|
||||
// stop unwinding when we leave package runtime.
|
||||
|
@ -35,6 +41,8 @@ func ExampleFrames() {
|
|||
break
|
||||
}
|
||||
fmt.Printf("- more:%v | %s\n", more, frame.Function)
|
||||
|
||||
// Check whether there are more frames to process after this one.
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -261,6 +261,27 @@ func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []*profile.Loca
|
|||
return p
|
||||
}
|
||||
|
||||
func cpuProfilingBroken() bool {
|
||||
switch runtime.GOOS {
|
||||
case "plan9":
|
||||
// Profiling unimplemented.
|
||||
return true
|
||||
case "aix":
|
||||
// See https://golang.org/issue/45170.
|
||||
return true
|
||||
case "ios", "dragonfly", "netbsd", "illumos", "solaris":
|
||||
// See https://golang.org/issue/13841.
|
||||
return true
|
||||
case "openbsd":
|
||||
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
|
||||
// See https://golang.org/issue/13841.
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// testCPUProfile runs f under the CPU profiler, checking for some conditions specified by need,
|
||||
// as interpreted by matches, and returns the parsed profile.
|
||||
func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []string, f func(dur time.Duration)) *profile.Profile {
|
||||
|
@ -276,16 +297,7 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri
|
|||
t.Skip("skipping on plan9")
|
||||
}
|
||||
|
||||
broken := false
|
||||
switch runtime.GOOS {
|
||||
// See https://golang.org/issue/45170 for AIX.
|
||||
case "ios", "dragonfly", "netbsd", "illumos", "solaris", "aix":
|
||||
broken = true
|
||||
case "openbsd":
|
||||
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
|
||||
broken = true
|
||||
}
|
||||
}
|
||||
broken := cpuProfilingBroken()
|
||||
|
||||
maxDuration := 5 * time.Second
|
||||
if testing.Short() && broken {
|
||||
|
@ -612,7 +624,7 @@ func growstack1() {
|
|||
|
||||
//go:noinline
|
||||
func growstack(n int) {
|
||||
var buf [8 << 16]byte
|
||||
var buf [8 << 18]byte
|
||||
use(buf)
|
||||
if n > 0 {
|
||||
growstack(n - 1)
|
||||
|
@ -620,7 +632,7 @@ func growstack(n int) {
|
|||
}
|
||||
|
||||
//go:noinline
|
||||
func use(x [8 << 16]byte) {}
|
||||
func use(x [8 << 18]byte) {}
|
||||
|
||||
func TestBlockProfile(t *testing.T) {
|
||||
type TestCase struct {
|
||||
|
|
|
@ -281,6 +281,8 @@ func setProcessCPUProfiler(hz int32) {
|
|||
it.it_value = it.it_interval
|
||||
setitimer(_ITIMER_PROF, &it, nil)
|
||||
} else {
|
||||
setitimer(_ITIMER_PROF, &itimerval{}, nil)
|
||||
|
||||
// If the Go signal handler should be disabled by default,
|
||||
// switch back to the signal handler that was installed
|
||||
// when we enabled profiling. We don't try to handle the case
|
||||
|
@ -304,8 +306,6 @@ func setProcessCPUProfiler(hz int32) {
|
|||
setsig(_SIGPROF, h)
|
||||
}
|
||||
}
|
||||
|
||||
setitimer(_ITIMER_PROF, &itimerval{}, nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,7 +383,7 @@ func preemptM(mp *m) {
|
|||
//go:nosplit
|
||||
func sigFetchG(c *sigctxt) *g {
|
||||
switch GOARCH {
|
||||
case "arm", "arm64":
|
||||
case "arm", "arm64", "ppc64", "ppc64le":
|
||||
if !iscgo && inVDSOPage(c.sigpc()) {
|
||||
// When using cgo, we save the g on TLS and load it from there
|
||||
// in sigtramp. Just use that.
|
||||
|
|
|
@ -69,8 +69,15 @@ func CallersFrames(callers []uintptr) *Frames {
|
|||
return f
|
||||
}
|
||||
|
||||
// Next returns frame information for the next caller.
|
||||
// If more is false, there are no more callers (the Frame value is valid).
|
||||
// Next returns a Frame representing the next call frame in the slice
|
||||
// of PC values. If it has already returned all call frames, Next
|
||||
// returns a zero Frame.
|
||||
//
|
||||
// The more result indicates whether the next call to Next will return
|
||||
// a valid Frame. It does not necessarily indicate whether this call
|
||||
// returned one.
|
||||
//
|
||||
// See the Frames example for idiomatic usage.
|
||||
func (ci *Frames) Next() (frame Frame, more bool) {
|
||||
for len(ci.frames) < 2 {
|
||||
// Find the next frame.
|
||||
|
|
|
@ -216,15 +216,45 @@ TEXT runtime·walltime(SB),NOSPLIT,$16-12
|
|||
MOVD (g_sched+gobuf_sp)(R7), R1 // Set SP to g0 stack
|
||||
|
||||
noswitch:
|
||||
SUB $16, R1 // Space for results
|
||||
RLDICR $0, R1, $59, R1 // Align for C code
|
||||
SUB $16, R1 // Space for results
|
||||
RLDICR $0, R1, $59, R1 // Align for C code
|
||||
MOVD R12, CTR
|
||||
MOVD R1, R4
|
||||
BL (CTR) // Call from VDSO
|
||||
MOVD $0, R0 // Restore R0
|
||||
MOVD 0(R1), R3 // sec
|
||||
MOVD 8(R1), R5 // nsec
|
||||
MOVD R15, R1 // Restore SP
|
||||
|
||||
// Store g on gsignal's stack, so if we receive a signal
|
||||
// during VDSO code we can find the g.
|
||||
// If we don't have a signal stack, we won't receive signal,
|
||||
// so don't bother saving g.
|
||||
// When using cgo, we already saved g on TLS, also don't save
|
||||
// g here.
|
||||
// Also don't save g if we are already on the signal stack.
|
||||
// We won't get a nested signal.
|
||||
MOVBZ runtime·iscgo(SB), R22
|
||||
CMP R22, $0
|
||||
BNE nosaveg
|
||||
MOVD m_gsignal(R21), R22 // g.m.gsignal
|
||||
CMP R22, $0
|
||||
BEQ nosaveg
|
||||
|
||||
CMP g, R22
|
||||
BEQ nosaveg
|
||||
MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
|
||||
MOVD g, (R22)
|
||||
|
||||
BL (CTR) // Call from VDSO
|
||||
|
||||
MOVD $0, (R22) // clear g slot, R22 is unchanged by C code
|
||||
|
||||
JMP finish
|
||||
|
||||
nosaveg:
|
||||
BL (CTR) // Call from VDSO
|
||||
|
||||
finish:
|
||||
MOVD $0, R0 // Restore R0
|
||||
MOVD 0(R1), R3 // sec
|
||||
MOVD 8(R1), R5 // nsec
|
||||
MOVD R15, R1 // Restore SP
|
||||
|
||||
// Restore vdsoPC, vdsoSP
|
||||
// We don't worry about being signaled between the two stores.
|
||||
|
@ -236,7 +266,7 @@ noswitch:
|
|||
MOVD 32(R1), R6
|
||||
MOVD R6, m_vdsoPC(R21)
|
||||
|
||||
finish:
|
||||
return:
|
||||
MOVD R3, sec+0(FP)
|
||||
MOVW R5, nsec+8(FP)
|
||||
RET
|
||||
|
@ -247,7 +277,7 @@ fallback:
|
|||
SYSCALL $SYS_clock_gettime
|
||||
MOVD 32(R1), R3
|
||||
MOVD 40(R1), R5
|
||||
JMP finish
|
||||
JMP return
|
||||
|
||||
TEXT runtime·nanotime1(SB),NOSPLIT,$16-8
|
||||
MOVD $1, R3 // CLOCK_MONOTONIC
|
||||
|
@ -283,7 +313,37 @@ noswitch:
|
|||
RLDICR $0, R1, $59, R1 // Align for C code
|
||||
MOVD R12, CTR
|
||||
MOVD R1, R4
|
||||
BL (CTR) // Call from VDSO
|
||||
|
||||
// Store g on gsignal's stack, so if we receive a signal
|
||||
// during VDSO code we can find the g.
|
||||
// If we don't have a signal stack, we won't receive signal,
|
||||
// so don't bother saving g.
|
||||
// When using cgo, we already saved g on TLS, also don't save
|
||||
// g here.
|
||||
// Also don't save g if we are already on the signal stack.
|
||||
// We won't get a nested signal.
|
||||
MOVBZ runtime·iscgo(SB), R22
|
||||
CMP R22, $0
|
||||
BNE nosaveg
|
||||
MOVD m_gsignal(R21), R22 // g.m.gsignal
|
||||
CMP R22, $0
|
||||
BEQ nosaveg
|
||||
|
||||
CMP g, R22
|
||||
BEQ nosaveg
|
||||
MOVD (g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
|
||||
MOVD g, (R22)
|
||||
|
||||
BL (CTR) // Call from VDSO
|
||||
|
||||
MOVD $0, (R22) // clear g slot, R22 is unchanged by C code
|
||||
|
||||
JMP finish
|
||||
|
||||
nosaveg:
|
||||
BL (CTR) // Call from VDSO
|
||||
|
||||
finish:
|
||||
MOVD $0, R0 // Restore R0
|
||||
MOVD 0(R1), R3 // sec
|
||||
MOVD 8(R1), R5 // nsec
|
||||
|
@ -299,7 +359,7 @@ noswitch:
|
|||
MOVD 32(R1), R6
|
||||
MOVD R6, m_vdsoPC(R21)
|
||||
|
||||
finish:
|
||||
return:
|
||||
// sec is in R3, nsec in R5
|
||||
// return nsec in R3
|
||||
MOVD $1000000000, R4
|
||||
|
@ -314,7 +374,7 @@ fallback:
|
|||
SYSCALL $SYS_clock_gettime
|
||||
MOVD 32(R1), R3
|
||||
MOVD 40(R1), R5
|
||||
JMP finish
|
||||
JMP return
|
||||
|
||||
TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
|
||||
MOVW how+0(FP), R3
|
||||
|
@ -469,7 +529,7 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
|
|||
// this might be called in external code context,
|
||||
// where g is not set.
|
||||
MOVBZ runtime·iscgo(SB), R6
|
||||
CMP R6, $0
|
||||
CMP R6, $0
|
||||
BEQ 2(PC)
|
||||
BL runtime·load_g(SB)
|
||||
|
||||
|
|
|
@ -252,6 +252,8 @@ import (
|
|||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var initRan bool
|
||||
|
@ -908,11 +910,6 @@ func (c *common) Cleanup(f func()) {
|
|||
c.cleanups = append(c.cleanups, fn)
|
||||
}
|
||||
|
||||
var tempDirReplacer struct {
|
||||
sync.Once
|
||||
r *strings.Replacer
|
||||
}
|
||||
|
||||
// TempDir returns a temporary directory for the test to use.
|
||||
// The directory is automatically removed by Cleanup when the test and
|
||||
// all its subtests complete.
|
||||
|
@ -936,13 +933,26 @@ func (c *common) TempDir() string {
|
|||
if nonExistent {
|
||||
c.Helper()
|
||||
|
||||
// os.MkdirTemp doesn't like path separators in its pattern,
|
||||
// so mangle the name to accommodate subtests.
|
||||
tempDirReplacer.Do(func() {
|
||||
tempDirReplacer.r = strings.NewReplacer("/", "_", "\\", "_", ":", "_")
|
||||
})
|
||||
pattern := tempDirReplacer.r.Replace(c.Name())
|
||||
|
||||
// Drop unusual characters (such as path separators or
|
||||
// characters interacting with globs) from the directory name to
|
||||
// avoid surprising os.MkdirTemp behavior.
|
||||
mapper := func(r rune) rune {
|
||||
if r < utf8.RuneSelf {
|
||||
const allowed = "!#$%&()+,-.=@^_{}~ "
|
||||
if '0' <= r && r <= '9' ||
|
||||
'a' <= r && r <= 'z' ||
|
||||
'A' <= r && r <= 'Z' {
|
||||
return r
|
||||
}
|
||||
if strings.ContainsRune(allowed, r) {
|
||||
return r
|
||||
}
|
||||
} else if unicode.IsLetter(r) || unicode.IsNumber(r) {
|
||||
return r
|
||||
}
|
||||
return -1
|
||||
}
|
||||
pattern := strings.Map(mapper, c.Name())
|
||||
c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
|
||||
if c.tempDirErr == nil {
|
||||
c.Cleanup(func() {
|
||||
|
|
|
@ -58,6 +58,9 @@ func TestTempDir(t *testing.T) {
|
|||
t.Run("test:subtest", testTempDir)
|
||||
t.Run("test/..", testTempDir)
|
||||
t.Run("../test", testTempDir)
|
||||
t.Run("test[]", testTempDir)
|
||||
t.Run("test*", testTempDir)
|
||||
t.Run("äöüéè", testTempDir)
|
||||
}
|
||||
|
||||
func testTempDir(t *testing.T) {
|
||||
|
@ -74,7 +77,7 @@ func testTempDir(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Errorf("directory %q stil exists: %v, isDir=%v", dir, fi, fi.IsDir())
|
||||
t.Errorf("directory %q still exists: %v, isDir=%v", dir, fi, fi.IsDir())
|
||||
default:
|
||||
if !t.Failed() {
|
||||
t.Fatal("never received dir channel")
|
||||
|
@ -108,6 +111,11 @@ func testTempDir(t *testing.T) {
|
|||
if len(files) > 0 {
|
||||
t.Errorf("unexpected %d files in TempDir: %v", len(files), files)
|
||||
}
|
||||
|
||||
glob := filepath.Join(dir, "*.txt")
|
||||
if _, err := filepath.Glob(glob); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetenv(t *testing.T) {
|
||||
|
|
|
@ -1340,7 +1340,7 @@ func UnixMicro(usec int64) Time {
|
|||
}
|
||||
|
||||
// IsDST reports whether the time in the configured location is in Daylight Savings Time.
|
||||
func (t *Time) IsDST() bool {
|
||||
func (t Time) IsDST() bool {
|
||||
_, _, _, _, isDST := t.loc.lookup(t.Unix())
|
||||
return isDST
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue