mirror of https://github.com/golang/go.git
[dev.boringcrypto.go1.11] all: merge go1.11.2 into dev.boringcrypto.go1.11
Change-Id: I05b1fd8b4d3354935b44fc8fce6ae86dd652c94b
This commit is contained in:
commit
35cf0d9f6b
|
|
@ -34,6 +34,7 @@ We encourage all Go users to subscribe to
|
|||
<p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="/doc/go1.11">Go 1.11</a> <small>(August 2018)</small></li>
|
||||
<li><a href="/doc/go1.10">Go 1.10</a> <small>(February 2018)</small></li>
|
||||
<li><a href="/doc/go1.9">Go 1.9</a> <small>(August 2017)</small></li>
|
||||
<li><a href="/doc/go1.8">Go 1.8</a> <small>(February 2017)</small></li>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,32 @@ in supported releases as needed by issuing minor revisions
|
|||
(for example, Go 1.6.1, Go 1.6.2, and so on).
|
||||
</p>
|
||||
|
||||
<h2 id="go1.11">go1.11 (released 2018/08/24)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.11 is a major release of Go.
|
||||
Read the <a href="/doc/go1.11">Go 1.11 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.11.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.11.1 (released 2018/10/01) includes fixes to the compiler, documentation, go
|
||||
command, runtime, and the <code>crypto/x509</code>, <code>encoding/json</code>,
|
||||
<code>go/types</code>, <code>net</code>, <code>net/http</code>, and
|
||||
<code>reflect</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.1">Go
|
||||
1.11.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.11.2 (released 2018/11/02) includes fixes to the compiler, linker,
|
||||
documentation, go command, and the <code>database/sql</code> and
|
||||
<code>go/types</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.2">Go
|
||||
1.11.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
|
||||
|
||||
<p>
|
||||
|
|
@ -65,6 +91,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.4">Go
|
|||
1.10.4 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.10.5 (released 2018/11/02) includes fixes to the go command, linker, runtime
|
||||
and the <code>database/sql</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.10.5">Go
|
||||
1.10.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ learned. You can {{if not $.GoogleCN}}<a href="//tour.golang.org/">take the tour
|
|||
online</a> or{{end}} install it locally with:
|
||||
</p>
|
||||
<pre>
|
||||
$ go get golang.org/x/tour/gotour
|
||||
$ go get golang.org/x/tour
|
||||
</pre>
|
||||
<p>
|
||||
This will place the <code>gotour</code> binary in your workspace's <code>bin</code> directory.
|
||||
This will place the <code>tour</code> binary in your workspace's <code>bin</code> directory.
|
||||
</p>
|
||||
|
||||
<h3 id="code"><a href="code.html">How to write Go code</a></h3>
|
||||
|
|
|
|||
|
|
@ -348,6 +348,20 @@ updating. See the <a href="go1.10.html#cgo">Go 1.10 release notes</a> for
|
|||
details. <!-- CL 126275, CL 127156, CL 122217, CL 122575, CL 123177 -->
|
||||
</p>
|
||||
|
||||
<h3 id="go_command">Go command</h3>
|
||||
|
||||
<p><!-- CL 126656 -->
|
||||
The environment variable <code>GOFLAGS</code> may now be used
|
||||
to set default flags for the <code>go</code> command.
|
||||
This is useful in certain situations.
|
||||
Linking can be noticeably slower on underpowered systems due to DWARF,
|
||||
and users may want to set <code>-ldflags=-w</code> by default.
|
||||
For modules, some users and CI systems will want vendoring always,
|
||||
so they should set <code>-mod=vendor</code> by default.
|
||||
For more information, see the <a href="/cmd/go/#hdr-Environment_variables"><code>go</code>
|
||||
command documentation</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="godoc">Godoc</h3>
|
||||
|
||||
<p>
|
||||
|
|
@ -396,7 +410,7 @@ details. <!-- CL 126275, CL 127156, CL 122217, CL 122575, CL 123177 -->
|
|||
</p>
|
||||
|
||||
<p><!-- CL 108679, CL 106156 -->
|
||||
On macOS and iOS, the runtime now uses <code>libSystem.so</code> instead of
|
||||
On macOS and iOS, the runtime now uses <code>libSystem.dylib</code> instead of
|
||||
calling the kernel directly. This should make Go binaries more
|
||||
compatible with future versions of macOS and iOS.
|
||||
The <a href="/pkg/syscall">syscall</a> package still makes direct
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ license that can be found in the LICENSE file.
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<!--
|
||||
Add the following polyfill for Microsoft Edge 17/18 support:
|
||||
<script src="https://cdn.jsdelivr.net/npm/text-encoding@0.7.0/lib/encoding.min.js"></script>
|
||||
(see https://caniuse.com/#feat=textencoder)
|
||||
-->
|
||||
<script src="wasm_exec.js"></script>
|
||||
<script>
|
||||
if (!WebAssembly.instantiateStreaming) { // polyfill
|
||||
|
|
|
|||
|
|
@ -121,6 +121,17 @@ func (n *Node) Int64() int64 {
|
|||
return n.Val().U.(*Mpint).Int64()
|
||||
}
|
||||
|
||||
// CanInt64 reports whether it is safe to call Int64() on n.
|
||||
func (n *Node) CanInt64() bool {
|
||||
if !Isconst(n, CTINT) {
|
||||
return false
|
||||
}
|
||||
|
||||
// if the value inside n cannot be represented as an int64, the
|
||||
// return value of Int64 is undefined
|
||||
return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0
|
||||
}
|
||||
|
||||
// Bool returns n as a bool.
|
||||
// n must be a boolean constant.
|
||||
func (n *Node) Bool() bool {
|
||||
|
|
|
|||
|
|
@ -1263,7 +1263,7 @@ func typecheck1(n *Node, top int) *Node {
|
|||
n.Op = OCALLFUNC
|
||||
if t.Etype != TFUNC {
|
||||
name := l.String()
|
||||
if isBuiltinFuncName(name) {
|
||||
if isBuiltinFuncName(name) && l.Name.Defn != nil {
|
||||
// be more specific when the function
|
||||
// name matches a predeclared function
|
||||
yyerror("cannot call non-function %s (type %v), declared at %s",
|
||||
|
|
|
|||
|
|
@ -3701,6 +3701,12 @@ func walkinrange(n *Node, init *Nodes) *Node {
|
|||
return n
|
||||
}
|
||||
|
||||
// Ensure that Int64() does not overflow on a and c (it'll happen
|
||||
// for any const above 2**63; see issue #27143).
|
||||
if !a.CanInt64() || !c.CanInt64() {
|
||||
return n
|
||||
}
|
||||
|
||||
if opl == OLT {
|
||||
// We have a < b && ...
|
||||
// We need a ≤ b && ... to safely use unsigned comparison tricks.
|
||||
|
|
|
|||
|
|
@ -197,7 +197,8 @@ func elimDeadAutosGeneric(f *Func) {
|
|||
panic("unhandled op with sym effect")
|
||||
}
|
||||
|
||||
if v.Uses == 0 || len(args) == 0 {
|
||||
if v.Uses == 0 && v.Op != OpNilCheck || len(args) == 0 {
|
||||
// Nil check has no use, but we need to keep it.
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1539,8 +1539,8 @@
|
|||
// Don't Move from memory if the values are likely to already be
|
||||
// in registers.
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [0] p3) d2 _)))
|
||||
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _)))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
|
|
@ -1548,12 +1548,12 @@
|
|||
&& registerizable(b, t3)
|
||||
&& o2 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr [0] p4) d3 _))))
|
||||
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
|
|
@ -1564,14 +1564,14 @@
|
|||
&& o3 == sizeof(t4)
|
||||
&& o2-o3 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr [o4] p4) d3
|
||||
(Store {t5} op5:(OffPtr [0] p5) d4 _)))))
|
||||
mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr <tt4> [o4] p4) d3
|
||||
(Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _)))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
|
|
@ -1585,16 +1585,16 @@
|
|||
&& o3-o4 == sizeof(t4)
|
||||
&& o2-o3 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3
|
||||
(Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <tt4> [o4] dst) d3
|
||||
(Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
|
||||
|
||||
// Same thing but with VarDef in the middle.
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(VarDef
|
||||
(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [0] p3) d2 _))))
|
||||
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
|
|
@ -1602,13 +1602,13 @@
|
|||
&& registerizable(b, t3)
|
||||
&& o2 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(VarDef
|
||||
(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr [0] p4) d3 _)))))
|
||||
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _)))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
|
|
@ -1619,15 +1619,15 @@
|
|||
&& o3 == sizeof(t4)
|
||||
&& o2-o3 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
|
||||
(Move {t1} [n] dst p1
|
||||
mem:(VarDef
|
||||
(Store {t2} op2:(OffPtr [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr [o4] p4) d3
|
||||
(Store {t5} op5:(OffPtr [0] p5) d4 _))))))
|
||||
(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1
|
||||
(Store {t3} op3:(OffPtr <tt3> [o3] p3) d2
|
||||
(Store {t4} op4:(OffPtr <tt4> [o4] p4) d3
|
||||
(Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _))))))
|
||||
&& isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5)
|
||||
&& alignof(t2) <= alignof(t1)
|
||||
&& alignof(t3) <= alignof(t1)
|
||||
|
|
@ -1641,10 +1641,10 @@
|
|||
&& o3-o4 == sizeof(t4)
|
||||
&& o2-o3 == sizeof(t3)
|
||||
&& n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
|
||||
-> (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3
|
||||
(Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
|
||||
-> (Store {t2} (OffPtr <tt2> [o2] dst) d1
|
||||
(Store {t3} (OffPtr <tt3> [o3] dst) d2
|
||||
(Store {t4} (OffPtr <tt4> [o4] dst) d3
|
||||
(Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
|
||||
|
||||
// Prefer to Zero and Store than to Move.
|
||||
(Move {t1} [n] dst p1
|
||||
|
|
|
|||
|
|
@ -425,13 +425,13 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
|
|||
//
|
||||
// Useful for i > 0; s[i-1].
|
||||
lim, ok := ft.limits[x.ID]
|
||||
if ok && lim.min > opMin[v.Op] {
|
||||
if ok && ((d == signed && lim.min > opMin[v.Op]) || (d == unsigned && lim.umin > 0)) {
|
||||
ft.update(parent, x, w, d, gt)
|
||||
}
|
||||
} else if x, delta := isConstDelta(w); x != nil && delta == 1 {
|
||||
// v >= x+1 && x < max ⇒ v > x
|
||||
lim, ok := ft.limits[x.ID]
|
||||
if ok && lim.max < opMax[w.Op] {
|
||||
if ok && ((d == signed && lim.max < opMax[w.Op]) || (d == unsigned && lim.umax < opUMax[w.Op])) {
|
||||
ft.update(parent, v, x, d, gt)
|
||||
}
|
||||
}
|
||||
|
|
@ -527,6 +527,11 @@ var opMax = map[Op]int64{
|
|||
OpAdd32: math.MaxInt32, OpSub32: math.MaxInt32,
|
||||
}
|
||||
|
||||
var opUMax = map[Op]uint64{
|
||||
OpAdd64: math.MaxUint64, OpSub64: math.MaxUint64,
|
||||
OpAdd32: math.MaxUint32, OpSub32: math.MaxUint32,
|
||||
}
|
||||
|
||||
// isNonNegative reports whether v is known to be non-negative.
|
||||
func (ft *factsTable) isNonNegative(v *Value) bool {
|
||||
if isNonNegative(v) {
|
||||
|
|
|
|||
|
|
@ -16223,9 +16223,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [0] p3) d2 _)))
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _)))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && o2 == sizeof(t3) && n == sizeof(t2) + sizeof(t3)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
|
|
@ -16242,6 +16242,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem.Args[1]
|
||||
|
|
@ -16255,6 +16256,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
if op3.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
|
|
@ -16265,14 +16267,14 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = 0
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
|
|
@ -16281,9 +16283,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [0] p4) d3 _))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && o3 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
|
|
@ -16300,6 +16302,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem.Args[1]
|
||||
|
|
@ -16313,6 +16316,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
o3 := op3.AuxInt
|
||||
p3 := op3.Args[0]
|
||||
d2 := mem_2.Args[1]
|
||||
|
|
@ -16326,6 +16330,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op4.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt4 := op4.Type
|
||||
if op4.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
|
|
@ -16336,21 +16341,21 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = o3
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
v1.AddArg(d2)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = t4
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
|
||||
v4.AuxInt = 0
|
||||
v4.AddArg(dst)
|
||||
v3.AddArg(v4)
|
||||
|
|
@ -16360,9 +16365,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [o4] p4) d3 (Store {t5} op5:(OffPtr [0] p5) d4 _)))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [o4] p4) d3 (Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _)))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && alignof(t5) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && registerizable(b, t5) && o4 == sizeof(t5) && o3-o4 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3 (Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [o4] dst) d3 (Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
|
|
@ -16379,6 +16384,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem.Args[1]
|
||||
|
|
@ -16392,6 +16398,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
o3 := op3.AuxInt
|
||||
p3 := op3.Args[0]
|
||||
d2 := mem_2.Args[1]
|
||||
|
|
@ -16405,6 +16412,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op4.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt4 := op4.Type
|
||||
o4 := op4.AuxInt
|
||||
p4 := op4.Args[0]
|
||||
d3 := mem_2_2.Args[1]
|
||||
|
|
@ -16418,6 +16426,7 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
if op5.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt5 := op5.Type
|
||||
if op5.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
|
|
@ -16428,28 +16437,28 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = o3
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
v1.AddArg(d2)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = t4
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
|
||||
v4.AuxInt = o4
|
||||
v4.AddArg(dst)
|
||||
v3.AddArg(v4)
|
||||
v3.AddArg(d3)
|
||||
v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v5.Aux = t5
|
||||
v6 := b.NewValue0(v.Pos, OpOffPtr, t5.(*types.Type))
|
||||
v6 := b.NewValue0(v.Pos, OpOffPtr, tt5)
|
||||
v6.AuxInt = 0
|
||||
v6.AddArg(dst)
|
||||
v5.AddArg(v6)
|
||||
|
|
@ -16465,9 +16474,9 @@ func rewriteValuegeneric_OpMove_0(v *Value) bool {
|
|||
func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [0] p3) d2 _))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [0] p3) d2 _))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && o2 == sizeof(t3) && n == sizeof(t2) + sizeof(t3)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [0] dst) d2 mem))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [0] dst) d2 mem))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
|
|
@ -16488,6 +16497,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem_0.Args[1]
|
||||
|
|
@ -16501,6 +16511,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
if op3.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
|
|
@ -16511,14 +16522,14 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = 0
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
|
|
@ -16527,9 +16538,9 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [0] p4) d3 _)))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [0] p4) d3 _)))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && o3 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [0] dst) d3 mem)))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [0] dst) d3 mem)))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
|
|
@ -16550,6 +16561,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem_0.Args[1]
|
||||
|
|
@ -16563,6 +16575,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
o3 := op3.AuxInt
|
||||
p3 := op3.Args[0]
|
||||
d2 := mem_0_2.Args[1]
|
||||
|
|
@ -16576,6 +16589,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op4.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt4 := op4.Type
|
||||
if op4.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
|
|
@ -16586,21 +16600,21 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = o3
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
v1.AddArg(d2)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = t4
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
|
||||
v4.AuxInt = 0
|
||||
v4.AddArg(dst)
|
||||
v3.AddArg(v4)
|
||||
|
|
@ -16610,9 +16624,9 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr [o2] p2) d1 (Store {t3} op3:(OffPtr [o3] p3) d2 (Store {t4} op4:(OffPtr [o4] p4) d3 (Store {t5} op5:(OffPtr [0] p5) d4 _))))))
|
||||
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} op2:(OffPtr <tt2> [o2] p2) d1 (Store {t3} op3:(OffPtr <tt3> [o3] p3) d2 (Store {t4} op4:(OffPtr <tt4> [o4] p4) d3 (Store {t5} op5:(OffPtr <tt5> [0] p5) d4 _))))))
|
||||
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && alignof(t5) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && registerizable(b, t5) && o4 == sizeof(t5) && o3-o4 == sizeof(t4) && o2-o3 == sizeof(t3) && n == sizeof(t2) + sizeof(t3) + sizeof(t4) + sizeof(t5)
|
||||
// result: (Store {t2} (OffPtr <t2.(*types.Type)> [o2] dst) d1 (Store {t3} (OffPtr <t3.(*types.Type)> [o3] dst) d2 (Store {t4} (OffPtr <t4.(*types.Type)> [o4] dst) d3 (Store {t5} (OffPtr <t5.(*types.Type)> [0] dst) d4 mem))))
|
||||
// result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [o4] dst) d3 (Store {t5} (OffPtr <tt5> [0] dst) d4 mem))))
|
||||
for {
|
||||
n := v.AuxInt
|
||||
t1 := v.Aux
|
||||
|
|
@ -16633,6 +16647,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op2.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt2 := op2.Type
|
||||
o2 := op2.AuxInt
|
||||
p2 := op2.Args[0]
|
||||
d1 := mem_0.Args[1]
|
||||
|
|
@ -16646,6 +16661,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op3.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt3 := op3.Type
|
||||
o3 := op3.AuxInt
|
||||
p3 := op3.Args[0]
|
||||
d2 := mem_0_2.Args[1]
|
||||
|
|
@ -16659,6 +16675,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op4.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt4 := op4.Type
|
||||
o4 := op4.AuxInt
|
||||
p4 := op4.Args[0]
|
||||
d3 := mem_0_2_2.Args[1]
|
||||
|
|
@ -16672,6 +16689,7 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
if op5.Op != OpOffPtr {
|
||||
break
|
||||
}
|
||||
tt5 := op5.Type
|
||||
if op5.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
|
|
@ -16682,28 +16700,28 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
|
|||
}
|
||||
v.reset(OpStore)
|
||||
v.Aux = t2
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, t2.(*types.Type))
|
||||
v0 := b.NewValue0(v.Pos, OpOffPtr, tt2)
|
||||
v0.AuxInt = o2
|
||||
v0.AddArg(dst)
|
||||
v.AddArg(v0)
|
||||
v.AddArg(d1)
|
||||
v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v1.Aux = t3
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, t3.(*types.Type))
|
||||
v2 := b.NewValue0(v.Pos, OpOffPtr, tt3)
|
||||
v2.AuxInt = o3
|
||||
v2.AddArg(dst)
|
||||
v1.AddArg(v2)
|
||||
v1.AddArg(d2)
|
||||
v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v3.Aux = t4
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, t4.(*types.Type))
|
||||
v4 := b.NewValue0(v.Pos, OpOffPtr, tt4)
|
||||
v4.AuxInt = o4
|
||||
v4.AddArg(dst)
|
||||
v3.AddArg(v4)
|
||||
v3.AddArg(d3)
|
||||
v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem)
|
||||
v5.Aux = t5
|
||||
v6 := b.NewValue0(v.Pos, OpOffPtr, t5.(*types.Type))
|
||||
v6 := b.NewValue0(v.Pos, OpOffPtr, tt5)
|
||||
v6.AuxInt = 0
|
||||
v6.AddArg(dst)
|
||||
v5.AddArg(v6)
|
||||
|
|
|
|||
|
|
@ -817,7 +817,7 @@ func (t *Type) ChanArgs() *Type {
|
|||
return t.Extra.(ChanArgs).T
|
||||
}
|
||||
|
||||
// FuncArgs returns the channel type for TFUNCARGS type t.
|
||||
// FuncArgs returns the func type for TFUNCARGS type t.
|
||||
func (t *Type) FuncArgs() *Type {
|
||||
t.wantEtype(TFUNCARGS)
|
||||
return t.Extra.(FuncArgs).T
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@
|
|||
// link against shared libraries previously created with
|
||||
// -buildmode=shared.
|
||||
// -mod mode
|
||||
// module download mode to use: readonly, release, or vendor.
|
||||
// module download mode to use: readonly or vendor.
|
||||
// See 'go help modules' for more.
|
||||
// -pkgdir dir
|
||||
// install and load all packages from dir instead of the usual locations.
|
||||
|
|
@ -889,7 +889,7 @@
|
|||
//
|
||||
// Usage:
|
||||
//
|
||||
// go mod download [-dir] [-json] [modules]
|
||||
// go mod download [-json] [modules]
|
||||
//
|
||||
// Download downloads the named modules, which can be module patterns selecting
|
||||
// dependencies of the main module or module queries of the form path@version.
|
||||
|
|
@ -1449,6 +1449,12 @@
|
|||
// The directory where the go command will write
|
||||
// temporary source files, packages, and binaries.
|
||||
//
|
||||
// Each entry in the GOFLAGS list must be a standalone flag.
|
||||
// Because the entries are space-separated, flag values must
|
||||
// not contain spaces. In some cases, you can provide multiple flag
|
||||
// values instead: for example, to set '-ldflags=-s -w'
|
||||
// you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'.
|
||||
//
|
||||
// Environment variables for use with cgo:
|
||||
//
|
||||
// CC
|
||||
|
|
|
|||
|
|
@ -507,6 +507,12 @@ General-purpose environment variables:
|
|||
The directory where the go command will write
|
||||
temporary source files, packages, and binaries.
|
||||
|
||||
Each entry in the GOFLAGS list must be a standalone flag.
|
||||
Because the entries are space-separated, flag values must
|
||||
not contain spaces. In some cases, you can provide multiple flag
|
||||
values instead: for example, to set '-ldflags=-s -w'
|
||||
you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'.
|
||||
|
||||
Environment variables for use with cgo:
|
||||
|
||||
CC
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
)
|
||||
|
||||
var cmdDownload = &base.Command{
|
||||
UsageLine: "go mod download [-dir] [-json] [modules]",
|
||||
UsageLine: "go mod download [-json] [modules]",
|
||||
Short: "download modules to local cache",
|
||||
Long: `
|
||||
Download downloads the named modules, which can be module patterns selecting
|
||||
|
|
|
|||
|
|
@ -694,6 +694,10 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
|
|||
return nil, "", err
|
||||
}
|
||||
|
||||
if err := ensureGitAttributes(r.dir); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// Incredibly, git produces different archives depending on whether
|
||||
// it is running on a Windows system or not, in an attempt to normalize
|
||||
// text file line endings. Setting -c core.autocrlf=input means only
|
||||
|
|
@ -709,3 +713,43 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
|
|||
|
||||
return ioutil.NopCloser(bytes.NewReader(archive)), "", nil
|
||||
}
|
||||
|
||||
// ensureGitAttributes makes sure export-subst and export-ignore features are
|
||||
// disabled for this repo. This is intended to be run prior to running git
|
||||
// archive so that zip files are generated that produce consistent ziphashes
|
||||
// for a given revision, independent of variables such as git version and the
|
||||
// size of the repo.
|
||||
//
|
||||
// See: https://github.com/golang/go/issues/27153
|
||||
func ensureGitAttributes(repoDir string) (err error) {
|
||||
const attr = "\n* -export-subst -export-ignore\n"
|
||||
|
||||
d := repoDir + "/info"
|
||||
p := d + "/attributes"
|
||||
|
||||
if err := os.MkdirAll(d, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
closeErr := f.Close()
|
||||
if closeErr != nil {
|
||||
err = closeErr
|
||||
}
|
||||
}()
|
||||
|
||||
b, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.HasSuffix(b, []byte(attr)) {
|
||||
_, err := f.WriteString(attr)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ and test commands:
|
|||
link against shared libraries previously created with
|
||||
-buildmode=shared.
|
||||
-mod mode
|
||||
module download mode to use: readonly, release, or vendor.
|
||||
module download mode to use: readonly or vendor.
|
||||
See 'go help modules' for more.
|
||||
-pkgdir dir
|
||||
install and load all packages from dir instead of the usual locations.
|
||||
|
|
|
|||
|
|
@ -224,7 +224,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
|
|||
if len(p.SFiles) > 0 {
|
||||
fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)
|
||||
}
|
||||
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc
|
||||
// GO386, GOARM, GOMIPS, etc.
|
||||
baseArch := strings.TrimSuffix(cfg.BuildContext.GOARCH, "le")
|
||||
fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(baseArch)))
|
||||
|
||||
// TODO(rsc): Convince compiler team not to add more magic environment variables,
|
||||
// or perhaps restrict the environment variables passed to subprocesses.
|
||||
|
|
@ -2075,14 +2077,37 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
|
|||
}
|
||||
|
||||
// gccld runs the gcc linker to create an executable from a set of object files.
|
||||
func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, objs []string) error {
|
||||
func (b *Builder) gccld(p *load.Package, objdir, outfile string, flags []string, objs []string) error {
|
||||
var cmd []string
|
||||
if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
|
||||
cmd = b.GxxCmd(p.Dir, objdir)
|
||||
} else {
|
||||
cmd = b.GccCmd(p.Dir, objdir)
|
||||
}
|
||||
return b.run(nil, p.Dir, p.ImportPath, b.cCompilerEnv(), cmd, "-o", out, objs, flags)
|
||||
|
||||
cmdargs := []interface{}{cmd, "-o", outfile, objs, flags}
|
||||
dir := p.Dir
|
||||
out, err := b.runOut(dir, b.cCompilerEnv(), cmdargs...)
|
||||
if len(out) > 0 {
|
||||
// Filter out useless linker warnings caused by bugs outside Go.
|
||||
// See also cmd/link/internal/ld's hostlink method.
|
||||
var save [][]byte
|
||||
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
|
||||
// golang.org/issue/26073 - Apple Xcode bug
|
||||
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
|
||||
continue
|
||||
}
|
||||
save = append(save, line)
|
||||
}
|
||||
out = bytes.Join(save, nil)
|
||||
if len(out) > 0 {
|
||||
b.showOutput(nil, dir, p.ImportPath, b.processOutput(out))
|
||||
if err != nil {
|
||||
err = errPrintedOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Grab these before main helpfully overwrites them.
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ var validLinkerFlags = []*regexp.Regexp{
|
|||
re(`-Wl,-e[=,][a-zA-Z0-9]*`),
|
||||
re(`-Wl,--enable-new-dtags`),
|
||||
re(`-Wl,--end-group`),
|
||||
re(`-Wl,--(no-)?export-dynamic`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]+`),
|
||||
re(`-Wl,-headerpad_max_install_names`),
|
||||
re(`-Wl,--no-undefined`),
|
||||
|
|
|
|||
|
|
@ -629,6 +629,9 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
|
|||
text = string(data)
|
||||
}
|
||||
|
||||
// Matching against workdir would be misleading.
|
||||
text = strings.Replace(text, ts.workdir, "$WORK", -1)
|
||||
|
||||
if neg {
|
||||
if re.MatchString(text) {
|
||||
if isGrep {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
# Set up fresh GOCACHE.
|
||||
env GOCACHE=$WORK/gocache
|
||||
mkdir $GOCACHE
|
||||
|
||||
# Building for mipsle without setting GOMIPS will use floating point registers.
|
||||
env GOARCH=mipsle
|
||||
env GOOS=linux
|
||||
go build -gcflags=-S f.go
|
||||
stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
|
||||
|
||||
# Clean cache
|
||||
go clean -cache
|
||||
|
||||
# Building with GOMIPS=softfloat will not use floating point registers
|
||||
env GOMIPS=softfloat
|
||||
go build -gcflags=-S f.go
|
||||
! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
|
||||
|
||||
# Clean cache
|
||||
go clean -cache
|
||||
|
||||
# Build without setting GOMIPS
|
||||
env GOMIPS=
|
||||
go build -gcflags=-S f.go
|
||||
stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
|
||||
|
||||
# Building with GOMIPS should still not use floating point registers.
|
||||
env GOMIPS=softfloat
|
||||
go build -gcflags=-S f.go
|
||||
! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+
|
||||
|
||||
-- f.go --
|
||||
package f
|
||||
|
||||
func F(x float64) float64 {
|
||||
return x + x
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
env GO111MODULE=on
|
||||
env GOPROXY=
|
||||
|
||||
# Testing that git export-subst is disabled
|
||||
[!net] skip
|
||||
[!exec:git] skip
|
||||
go build
|
||||
|
||||
-- x.go --
|
||||
package x
|
||||
|
||||
import _ "github.com/jasonkeene/export-subst"
|
||||
|
||||
-- go.mod --
|
||||
module x
|
||||
|
||||
require github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626
|
||||
|
||||
-- go.sum --
|
||||
github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626 h1:AUkXi/xFnm7lH2pgtvVkGb7buRn1ywFHw+xDpZ29Rz0=
|
||||
github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626/go.mod h1:DwJXqVtrgrQkv3Giuf2Jh4YyubVe7y41S1eOIaysTJw=
|
||||
|
|
@ -1324,9 +1324,24 @@ func (ctxt *Link) hostlink() {
|
|||
ctxt.Logf("\n")
|
||||
}
|
||||
|
||||
if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
|
||||
out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput()
|
||||
if err != nil {
|
||||
Exitf("running %s failed: %v\n%s", argv[0], err, out)
|
||||
} else if len(out) > 0 {
|
||||
}
|
||||
|
||||
// Filter out useless linker warnings caused by bugs outside Go.
|
||||
// See also cmd/go/internal/work/exec.go's gccld method.
|
||||
var save [][]byte
|
||||
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
|
||||
// golang.org/issue/26073 - Apple Xcode bug
|
||||
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
|
||||
continue
|
||||
}
|
||||
save = append(save, line)
|
||||
}
|
||||
out = bytes.Join(save, nil)
|
||||
|
||||
if len(out) > 0 {
|
||||
// always print external output even if the command is successful, so that we don't
|
||||
// swallow linker warnings (see https://golang.org/issue/17935).
|
||||
ctxt.Logf("%s", out)
|
||||
|
|
|
|||
|
|
@ -685,13 +685,14 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
|
|||
}
|
||||
ctx.emitSlice(&fakeMarkStart, text)
|
||||
case trace.EvGCSweepStart:
|
||||
slice := ctx.emitSlice(ev, "SWEEP")
|
||||
slice := ctx.makeSlice(ev, "SWEEP")
|
||||
if done := ev.Link; done != nil && done.Args[0] != 0 {
|
||||
slice.Arg = struct {
|
||||
Swept uint64 `json:"Swept bytes"`
|
||||
Reclaimed uint64 `json:"Reclaimed bytes"`
|
||||
}{done.Args[0], done.Args[1]}
|
||||
}
|
||||
ctx.emit(slice)
|
||||
case trace.EvGoStart, trace.EvGoStartLabel:
|
||||
info := getGInfo(ev.G)
|
||||
if ev.Type == trace.EvGoStartLabel {
|
||||
|
|
@ -846,7 +847,11 @@ func (ctx *traceContext) proc(ev *trace.Event) uint64 {
|
|||
}
|
||||
}
|
||||
|
||||
func (ctx *traceContext) emitSlice(ev *trace.Event, name string) *ViewerEvent {
|
||||
func (ctx *traceContext) emitSlice(ev *trace.Event, name string) {
|
||||
ctx.emit(ctx.makeSlice(ev, name))
|
||||
}
|
||||
|
||||
func (ctx *traceContext) makeSlice(ev *trace.Event, name string) *ViewerEvent {
|
||||
// If ViewerEvent.Dur is not a positive value,
|
||||
// trace viewer handles it as a non-terminating time interval.
|
||||
// Avoid it by setting the field with a small value.
|
||||
|
|
@ -885,7 +890,6 @@ func (ctx *traceContext) emitSlice(ev *trace.Event, name string) *ViewerEvent {
|
|||
sl.Cname = colorLightGrey
|
||||
}
|
||||
}
|
||||
ctx.emit(sl)
|
||||
return sl
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -906,8 +906,8 @@ func validHostname(host string) bool {
|
|||
if c == '-' && j != 0 {
|
||||
continue
|
||||
}
|
||||
if c == '_' {
|
||||
// _ is not a valid character in hostnames, but it's commonly
|
||||
if c == '_' || c == ':' {
|
||||
// Not valid characters in hostnames, but commonly
|
||||
// found in deployments outside the WebPKI.
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1881,6 +1881,7 @@ func TestValidHostname(t *testing.T) {
|
|||
{"foo.*.example.com", false},
|
||||
{"exa_mple.com", true},
|
||||
{"foo,bar", false},
|
||||
{"project-dev:us-central1:main", true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if got := validHostname(tt.host); got != tt.want {
|
||||
|
|
|
|||
|
|
@ -1322,11 +1322,13 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
|
|||
err: err,
|
||||
}
|
||||
return true
|
||||
} else if err == nil && !db.closed && db.maxIdleConnsLocked() > len(db.freeConn) {
|
||||
db.freeConn = append(db.freeConn, dc)
|
||||
} else if err == nil && !db.closed {
|
||||
if db.maxIdleConnsLocked() > len(db.freeConn) {
|
||||
db.freeConn = append(db.freeConn, dc)
|
||||
db.startCleanerLocked()
|
||||
return true
|
||||
}
|
||||
db.maxIdleClosed++
|
||||
db.startCleanerLocked()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3415,6 +3415,58 @@ func TestConnectionLeak(t *testing.T) {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestStatsMaxIdleClosedZero(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
db.SetMaxOpenConns(1)
|
||||
db.SetMaxIdleConns(1)
|
||||
db.SetConnMaxLifetime(0)
|
||||
|
||||
preMaxIdleClosed := db.Stats().MaxIdleClosed
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
rows, err := db.Query("SELECT|people|name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
|
||||
st := db.Stats()
|
||||
maxIdleClosed := st.MaxIdleClosed - preMaxIdleClosed
|
||||
t.Logf("MaxIdleClosed: %d", maxIdleClosed)
|
||||
if maxIdleClosed != 0 {
|
||||
t.Fatal("expected 0 max idle closed conns, got: ", maxIdleClosed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsMaxIdleClosedTen(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
db.SetMaxOpenConns(1)
|
||||
db.SetMaxIdleConns(0)
|
||||
db.SetConnMaxLifetime(0)
|
||||
|
||||
preMaxIdleClosed := db.Stats().MaxIdleClosed
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
rows, err := db.Query("SELECT|people|name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
|
||||
st := db.Stats()
|
||||
maxIdleClosed := st.MaxIdleClosed - preMaxIdleClosed
|
||||
t.Logf("MaxIdleClosed: %d", maxIdleClosed)
|
||||
if maxIdleClosed != 10 {
|
||||
t.Fatal("expected 0 max idle closed conns, got: ", maxIdleClosed)
|
||||
}
|
||||
}
|
||||
|
||||
type nvcDriver struct {
|
||||
fakeDriver
|
||||
skipNamedValueCheck bool
|
||||
|
|
|
|||
|
|
@ -672,6 +672,7 @@ func (d *decodeState) object(v reflect.Value) error {
|
|||
}
|
||||
|
||||
var mapElem reflect.Value
|
||||
originalErrorContext := d.errorContext
|
||||
|
||||
for {
|
||||
// Read opening " of string key or closing }.
|
||||
|
|
@ -832,8 +833,7 @@ func (d *decodeState) object(v reflect.Value) error {
|
|||
return errPhase
|
||||
}
|
||||
|
||||
d.errorContext.Struct = ""
|
||||
d.errorContext.Field = ""
|
||||
d.errorContext = originalErrorContext
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -991,7 +991,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
if fromQuoted {
|
||||
return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
|
||||
}
|
||||
return &UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}
|
||||
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
case reflect.Interface:
|
||||
n, err := d.convertNumber(s)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -371,6 +371,10 @@ func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error {
|
|||
return (*intWithMarshalText)(b).UnmarshalText(data)
|
||||
}
|
||||
|
||||
type mapStringToStringData struct {
|
||||
Data map[string]string `json:"data"`
|
||||
}
|
||||
|
||||
type unmarshalTest struct {
|
||||
in string
|
||||
ptr interface{}
|
||||
|
|
@ -401,6 +405,7 @@ var unmarshalTests = []unmarshalTest{
|
|||
{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
|
||||
{in: "null", ptr: new(interface{}), out: nil},
|
||||
{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}},
|
||||
{in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(""), 8, "T", "X"}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}},
|
||||
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
|
||||
{in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true},
|
||||
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
|
||||
|
|
@ -866,6 +871,18 @@ var unmarshalTests = []unmarshalTest{
|
|||
err: fmt.Errorf("json: unknown field \"extra\""),
|
||||
disallowUnknownFields: true,
|
||||
},
|
||||
// issue 26444
|
||||
// UnmarshalTypeError without field & struct values
|
||||
{
|
||||
in: `{"data":{"test1": "bob", "test2": 123}}`,
|
||||
ptr: new(mapStringToStringData),
|
||||
err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"},
|
||||
},
|
||||
{
|
||||
in: `{"data":{"test1": 123, "test2": "bob"}}`,
|
||||
ptr: new(mapStringToStringData),
|
||||
err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMarshal(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -261,6 +261,8 @@ func TestTypesInfo(t *testing.T) {
|
|||
{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
|
||||
{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
|
||||
{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`},
|
||||
{`package x3; var x = panic("");`, `panic`, `func(interface{})`},
|
||||
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
// panic(x)
|
||||
// record panic call if inside a function with result parameters
|
||||
// (for use in Checker.isTerminating)
|
||||
if check.sig.results.Len() > 0 {
|
||||
if check.sig != nil && check.sig.results.Len() > 0 {
|
||||
// function has result parameters
|
||||
p := check.isPanic
|
||||
if p == nil {
|
||||
|
|
|
|||
|
|
@ -355,3 +355,70 @@ func TestIssue25627(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue28005(t *testing.T) {
|
||||
// method names must match defining interface name for this test
|
||||
// (see last comment in this function)
|
||||
sources := [...]string{
|
||||
"package p; type A interface{ A() }",
|
||||
"package p; type B interface{ B() }",
|
||||
"package p; type X interface{ A; B }",
|
||||
}
|
||||
|
||||
// compute original file ASTs
|
||||
var orig [len(sources)]*ast.File
|
||||
for i, src := range sources {
|
||||
f, err := parser.ParseFile(fset, "", src, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
orig[i] = f
|
||||
}
|
||||
|
||||
// run the test for all order permutations of the incoming files
|
||||
for _, perm := range [][len(sources)]int{
|
||||
{0, 1, 2},
|
||||
{0, 2, 1},
|
||||
{1, 0, 2},
|
||||
{1, 2, 0},
|
||||
{2, 0, 1},
|
||||
{2, 1, 0},
|
||||
} {
|
||||
// create file order permutation
|
||||
files := make([]*ast.File, len(sources))
|
||||
for i := range perm {
|
||||
files[i] = orig[perm[i]]
|
||||
}
|
||||
|
||||
// type-check package with given file order permutation
|
||||
var conf Config
|
||||
info := &Info{Defs: make(map[*ast.Ident]Object)}
|
||||
_, err := conf.Check("", fset, files, info)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// look for interface object X
|
||||
var obj Object
|
||||
for name, def := range info.Defs {
|
||||
if name.Name == "X" {
|
||||
obj = def
|
||||
break
|
||||
}
|
||||
}
|
||||
if obj == nil {
|
||||
t.Fatal("interface not found")
|
||||
}
|
||||
iface := obj.Type().Underlying().(*Interface) // I must be an interface
|
||||
|
||||
// Each iface method m is embedded; and m's receiver base type name
|
||||
// must match the method's name per the choice in the source file.
|
||||
for i := 0; i < iface.NumMethods(); i++ {
|
||||
m := iface.Method(i)
|
||||
recvName := m.Type().(*Signature).Recv().Type().(*Named).Obj().Name()
|
||||
if recvName != m.Name() {
|
||||
t.Errorf("perm %v: got recv %s; want %s", perm, recvName, m.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -571,6 +571,15 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
|
|||
recvTyp = def
|
||||
}
|
||||
|
||||
// Correct receiver type for all methods explicitly declared
|
||||
// by this interface after we're done with type-checking at
|
||||
// this level. See comment below for details.
|
||||
check.later(func() {
|
||||
for _, m := range ityp.methods {
|
||||
m.typ.(*Signature).recv.typ = recvTyp
|
||||
}
|
||||
})
|
||||
|
||||
// collect methods
|
||||
var sigfix []*methodInfo
|
||||
for i, minfo := range info.methods {
|
||||
|
|
@ -580,9 +589,27 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
|
|||
pos := name.Pos()
|
||||
// Don't type-check signature yet - use an
|
||||
// empty signature now and update it later.
|
||||
// Since we know the receiver, set it up now
|
||||
// (required to avoid crash in ptrRecv; see
|
||||
// e.g. test case for issue 6638).
|
||||
// But set up receiver since we know it and
|
||||
// its position, and because interface method
|
||||
// signatures don't get a receiver via regular
|
||||
// type-checking (there isn't a receiver in the
|
||||
// method's AST). Setting the receiver type is
|
||||
// also important for ptrRecv() (see methodset.go).
|
||||
//
|
||||
// Note: For embedded methods, the receiver type
|
||||
// should be the type of the interface that declared
|
||||
// the methods in the first place. Since we get the
|
||||
// methods here via methodInfo, which may be computed
|
||||
// before we have all relevant interface types, we use
|
||||
// the current interface's type (recvType). This may be
|
||||
// the type of the interface embedding the interface that
|
||||
// declared the methods. This doesn't matter for type-
|
||||
// checking (we only care about the receiver type for
|
||||
// the ptrRecv predicate, and it's never a pointer recv
|
||||
// for interfaces), but it matters for go/types clients
|
||||
// and for printing. We correct the receiver after type-
|
||||
// checking.
|
||||
//
|
||||
// TODO(gri) Consider marking methods signatures
|
||||
// as incomplete, for better error messages. See
|
||||
// also the T4 and T5 tests in testdata/cycles2.src.
|
||||
|
|
|
|||
|
|
@ -38,5 +38,11 @@ func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
|
|||
done, err := wsrv.ExecIO(o, func(o *operation) error {
|
||||
return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
|
||||
})
|
||||
if err == nil {
|
||||
// Some versions of Windows (Windows 10 1803) do not set
|
||||
// file position after TransmitFile completes.
|
||||
// So just use Seek to set file position.
|
||||
_, err = syscall.Seek(o.handle, curpos+int64(done), 0)
|
||||
}
|
||||
return int64(done), err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,20 @@ import (
|
|||
"golang_org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
var (
|
||||
errLameReferral = errors.New("lame referral")
|
||||
errCannotUnmarshalDNSMessage = errors.New("cannot unmarshal DNS message")
|
||||
errCannotMarshalDNSMessage = errors.New("cannot marshal DNS message")
|
||||
errServerMisbehaving = errors.New("server misbehaving")
|
||||
errInvalidDNSResponse = errors.New("invalid DNS response")
|
||||
errNoAnswerFromDNSServer = errors.New("no answer from DNS server")
|
||||
|
||||
// errServerTemporarlyMisbehaving is like errServerMisbehaving, except
|
||||
// that when it gets translated to a DNSError, the IsTemporary field
|
||||
// gets set to true.
|
||||
errServerTemporarlyMisbehaving = errors.New("server misbehaving")
|
||||
)
|
||||
|
||||
func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err error) {
|
||||
id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
|
||||
b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true})
|
||||
|
|
@ -105,14 +119,14 @@ func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte)
|
|||
var p dnsmessage.Parser
|
||||
h, err := p.Start(b[:n])
|
||||
if err != nil {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
|
||||
}
|
||||
q, err := p.Question()
|
||||
if err != nil {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
|
||||
}
|
||||
if !checkResponse(id, query, h, q) {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
|
||||
}
|
||||
return p, h, nil
|
||||
}
|
||||
|
|
@ -122,7 +136,7 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
|
|||
q.Class = dnsmessage.ClassINET
|
||||
id, udpReq, tcpReq, err := newRequest(q)
|
||||
if err != nil {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot marshal DNS message")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
|
||||
}
|
||||
for _, network := range []string{"udp", "tcp"} {
|
||||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
|
||||
|
|
@ -147,31 +161,31 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que
|
|||
return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err)
|
||||
}
|
||||
if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone {
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
|
||||
}
|
||||
if h.Truncated { // see RFC 5966
|
||||
continue
|
||||
}
|
||||
return p, h, nil
|
||||
}
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("no answer from DNS server")
|
||||
return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
|
||||
}
|
||||
|
||||
// checkHeader performs basic sanity checks on the header.
|
||||
func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string) error {
|
||||
if h.RCode == dnsmessage.RCodeNameError {
|
||||
return errNoSuchHost
|
||||
}
|
||||
|
||||
_, err := p.AnswerHeader()
|
||||
if err != nil && err != dnsmessage.ErrSectionDone {
|
||||
return &DNSError{
|
||||
Err: "cannot unmarshal DNS message",
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
return errCannotUnmarshalDNSMessage
|
||||
}
|
||||
|
||||
// libresolv continues to the next server when it receives
|
||||
// an invalid referral response. See golang.org/issue/15434.
|
||||
if h.RCode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
|
||||
return &DNSError{Err: "lame referral", Name: name, Server: server}
|
||||
return errLameReferral
|
||||
}
|
||||
|
||||
if h.RCode != dnsmessage.RCodeSuccess && h.RCode != dnsmessage.RCodeNameError {
|
||||
|
|
@ -180,11 +194,10 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string)
|
|||
// a name error and we didn't get success,
|
||||
// the server is behaving incorrectly or
|
||||
// having temporary trouble.
|
||||
err := &DNSError{Err: "server misbehaving", Name: name, Server: server}
|
||||
if h.RCode == dnsmessage.RCodeServerFailure {
|
||||
err.IsTemporary = true
|
||||
return errServerTemporarlyMisbehaving
|
||||
}
|
||||
return err
|
||||
return errServerMisbehaving
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -194,28 +207,16 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type, name, server stri
|
|||
for {
|
||||
h, err := p.AnswerHeader()
|
||||
if err == dnsmessage.ErrSectionDone {
|
||||
return &DNSError{
|
||||
Err: errNoSuchHost.Error(),
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
return errNoSuchHost
|
||||
}
|
||||
if err != nil {
|
||||
return &DNSError{
|
||||
Err: "cannot unmarshal DNS message",
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
return errCannotUnmarshalDNSMessage
|
||||
}
|
||||
if h.Type == qtype {
|
||||
return nil
|
||||
}
|
||||
if err := p.SkipAnswer(); err != nil {
|
||||
return &DNSError{
|
||||
Err: "cannot unmarshal DNS message",
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
return errCannotUnmarshalDNSMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -229,7 +230,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string,
|
|||
|
||||
n, err := dnsmessage.NewName(name)
|
||||
if err != nil {
|
||||
return dnsmessage.Parser{}, "", errors.New("cannot marshal DNS message")
|
||||
return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage
|
||||
}
|
||||
q := dnsmessage.Question{
|
||||
Name: n,
|
||||
|
|
@ -243,38 +244,62 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string,
|
|||
|
||||
p, h, err := r.exchange(ctx, server, q, cfg.timeout)
|
||||
if err != nil {
|
||||
lastErr = &DNSError{
|
||||
dnsErr := &DNSError{
|
||||
Err: err.Error(),
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
if nerr, ok := err.(Error); ok && nerr.Timeout() {
|
||||
lastErr.(*DNSError).IsTimeout = true
|
||||
dnsErr.IsTimeout = true
|
||||
}
|
||||
// Set IsTemporary for socket-level errors. Note that this flag
|
||||
// may also be used to indicate a SERVFAIL response.
|
||||
if _, ok := err.(*OpError); ok {
|
||||
lastErr.(*DNSError).IsTemporary = true
|
||||
dnsErr.IsTemporary = true
|
||||
}
|
||||
lastErr = dnsErr
|
||||
continue
|
||||
}
|
||||
|
||||
// The name does not exist, so trying another server won't help.
|
||||
//
|
||||
// TODO: indicate this in a more obvious way, such as a field on DNSError?
|
||||
if h.RCode == dnsmessage.RCodeNameError {
|
||||
return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
|
||||
}
|
||||
|
||||
lastErr = checkHeader(&p, h, name, server)
|
||||
if lastErr != nil {
|
||||
if err := checkHeader(&p, h, name, server); err != nil {
|
||||
dnsErr := &DNSError{
|
||||
Err: err.Error(),
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
if err == errServerTemporarlyMisbehaving {
|
||||
dnsErr.IsTemporary = true
|
||||
}
|
||||
if err == errNoSuchHost {
|
||||
// The name does not exist, so trying
|
||||
// another server won't help.
|
||||
//
|
||||
// TODO: indicate this in a more
|
||||
// obvious way, such as a field on
|
||||
// DNSError?
|
||||
return p, server, dnsErr
|
||||
}
|
||||
lastErr = dnsErr
|
||||
continue
|
||||
}
|
||||
|
||||
lastErr = skipToAnswer(&p, qtype, name, server)
|
||||
if lastErr == nil {
|
||||
err = skipToAnswer(&p, qtype, name, server)
|
||||
if err == nil {
|
||||
return p, server, nil
|
||||
}
|
||||
lastErr = &DNSError{
|
||||
Err: err.Error(),
|
||||
Name: name,
|
||||
Server: server,
|
||||
}
|
||||
if err == errNoSuchHost {
|
||||
// The name does not exist, so trying another
|
||||
// server won't help.
|
||||
//
|
||||
// TODO: indicate this in a more obvious way,
|
||||
// such as a field on DNSError?
|
||||
return p, server, lastErr
|
||||
}
|
||||
}
|
||||
}
|
||||
return dnsmessage.Parser{}, "", lastErr
|
||||
|
|
|
|||
|
|
@ -1427,28 +1427,35 @@ func TestDNSGoroutineRace(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func lookupWithFake(fake fakeDNSServer, name string, typ dnsmessage.Type) error {
|
||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||
|
||||
resolvConf.mu.RLock()
|
||||
conf := resolvConf.dnsConfig
|
||||
resolvConf.mu.RUnlock()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
_, _, err := r.tryOneName(ctx, conf, name, typ)
|
||||
return err
|
||||
}
|
||||
|
||||
// Issue 8434: verify that Temporary returns true on an error when rcode
|
||||
// is SERVFAIL
|
||||
func TestIssue8434(t *testing.T) {
|
||||
msg := dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
RCode: dnsmessage.RCodeServerFailure,
|
||||
err := lookupWithFake(fakeDNSServer{
|
||||
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
return dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeServerFailure,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
b, err := msg.Pack()
|
||||
if err != nil {
|
||||
t.Fatal("Pack failed:", err)
|
||||
}
|
||||
var p dnsmessage.Parser
|
||||
h, err := p.Start(b)
|
||||
if err != nil {
|
||||
t.Fatal("Start failed:", err)
|
||||
}
|
||||
if err := p.SkipAllQuestions(); err != nil {
|
||||
t.Fatal("SkipAllQuestions failed:", err)
|
||||
}
|
||||
|
||||
err = checkHeader(&p, h, "golang.org", "foo:53")
|
||||
}, "golang.org.", dnsmessage.TypeALL)
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
|
|
@ -1464,50 +1471,76 @@ func TestIssue8434(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Issue 12778: verify that NXDOMAIN without RA bit errors as
|
||||
// "no such host" and not "server misbehaving"
|
||||
// TestNoSuchHost verifies that tryOneName works correctly when the domain does
|
||||
// not exist.
|
||||
//
|
||||
// Issue 12778: verify that NXDOMAIN without RA bit errors as "no such host"
|
||||
// and not "server misbehaving"
|
||||
//
|
||||
// Issue 25336: verify that NXDOMAIN errors fail fast.
|
||||
func TestIssue12778(t *testing.T) {
|
||||
lookups := 0
|
||||
fake := fakeDNSServer{
|
||||
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
lookups++
|
||||
return dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeNameError,
|
||||
RecursionAvailable: false,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}, nil
|
||||
//
|
||||
// Issue 27525: verify that empty answers fail fast.
|
||||
func TestNoSuchHost(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
f func(string, string, dnsmessage.Message, time.Time) (dnsmessage.Message, error)
|
||||
}{
|
||||
{
|
||||
"NXDOMAIN",
|
||||
func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
return dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeNameError,
|
||||
RecursionAvailable: false,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
"no answers",
|
||||
func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
return dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeSuccess,
|
||||
RecursionAvailable: false,
|
||||
Authoritative: true,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||
|
||||
resolvConf.mu.RLock()
|
||||
conf := resolvConf.dnsConfig
|
||||
resolvConf.mu.RUnlock()
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
lookups := 0
|
||||
err := lookupWithFake(fakeDNSServer{
|
||||
rh: func(n, s string, q dnsmessage.Message, d time.Time) (dnsmessage.Message, error) {
|
||||
lookups++
|
||||
return test.f(n, s, q, d)
|
||||
},
|
||||
}, ".", dnsmessage.TypeALL)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
if lookups != 1 {
|
||||
t.Errorf("got %d lookups, wanted 1", lookups)
|
||||
}
|
||||
|
||||
_, _, err := r.tryOneName(ctx, conf, ".", dnsmessage.TypeALL)
|
||||
|
||||
if lookups != 1 {
|
||||
t.Errorf("got %d lookups, wanted 1", lookups)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
de, ok := err.(*DNSError)
|
||||
if !ok {
|
||||
t.Fatalf("err = %#v; wanted a *net.DNSError", err)
|
||||
}
|
||||
if de.Err != errNoSuchHost.Error() {
|
||||
t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
de, ok := err.(*DNSError)
|
||||
if !ok {
|
||||
t.Fatalf("err = %#v; wanted a *net.DNSError", err)
|
||||
}
|
||||
if de.Err != errNoSuchHost.Error() {
|
||||
t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1535,3 +1568,56 @@ func TestDNSDialTCP(t *testing.T) {
|
|||
t.Fatal("exhange failed:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 27763: verify that two strings in one TXT record are concatenated.
|
||||
func TestTXTRecordTwoStrings(t *testing.T) {
|
||||
fake := fakeDNSServer{
|
||||
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
r := dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.Header.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeSuccess,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
Answers: []dnsmessage.Resource{
|
||||
{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: q.Questions[0].Name,
|
||||
Type: dnsmessage.TypeA,
|
||||
Class: dnsmessage.ClassINET,
|
||||
},
|
||||
Body: &dnsmessage.TXTResource{
|
||||
TXT: []string{"string1 ", "string2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: q.Questions[0].Name,
|
||||
Type: dnsmessage.TypeA,
|
||||
Class: dnsmessage.ClassINET,
|
||||
},
|
||||
Body: &dnsmessage.TXTResource{
|
||||
TXT: []string{"onestring"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return r, nil
|
||||
},
|
||||
}
|
||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||
txt, err := r.lookupTXT(context.Background(), "golang.org")
|
||||
if err != nil {
|
||||
t.Fatal("LookupTXT failed:", err)
|
||||
}
|
||||
if want := 2; len(txt) != want {
|
||||
t.Fatalf("len(txt), got %d, want %d", len(txt), want)
|
||||
}
|
||||
if want := "string1 string2"; txt[0] != want {
|
||||
t.Errorf("txt[0], got %q, want %q", txt[0], want)
|
||||
}
|
||||
if want := "onestring"; txt[1] != want {
|
||||
t.Errorf("txt[1], got %q, want %q", txt[1], want)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
|
|||
|
||||
b := result.Get("body")
|
||||
var body io.ReadCloser
|
||||
if b != js.Undefined() {
|
||||
// The body is undefined when the browser does not support streaming response bodies (Firefox),
|
||||
// and null in certain error cases, i.e. when the request is blocked because of CORS settings.
|
||||
if b != js.Undefined() && b != js.Null() {
|
||||
body = &streamReader{stream: b.Call("getReader")}
|
||||
} else {
|
||||
// Fall back to using ArrayBuffer
|
||||
|
|
|
|||
|
|
@ -299,11 +299,21 @@ func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error)
|
|||
Server: server,
|
||||
}
|
||||
}
|
||||
if len(txts) == 0 {
|
||||
txts = txt.TXT
|
||||
} else {
|
||||
txts = append(txts, txt.TXT...)
|
||||
// Multiple strings in one TXT record need to be
|
||||
// concatenated without separator to be consistent
|
||||
// with previous Go resolver.
|
||||
n := 0
|
||||
for _, s := range txt.TXT {
|
||||
n += len(s)
|
||||
}
|
||||
txtJoin := make([]byte, 0, n)
|
||||
for _, s := range txt.TXT {
|
||||
txtJoin = append(txtJoin, s...)
|
||||
}
|
||||
if len(txts) == 0 {
|
||||
txts = make([]string, 0, 1)
|
||||
}
|
||||
txts = append(txts, string(txtJoin))
|
||||
}
|
||||
return txts, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ func testSpliceBig(t *testing.T) {
|
|||
func testSpliceHonorsLimitedReader(t *testing.T) {
|
||||
t.Run("stopsAfterN", testSpliceStopsAfterN)
|
||||
t.Run("updatesN", testSpliceUpdatesN)
|
||||
t.Run("readerAtLimit", testSpliceReaderAtLimit)
|
||||
}
|
||||
|
||||
func testSpliceStopsAfterN(t *testing.T) {
|
||||
|
|
@ -208,7 +209,7 @@ func testSpliceUpdatesN(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func testSpliceReaderAtEOF(t *testing.T) {
|
||||
func testSpliceReaderAtLimit(t *testing.T) {
|
||||
clientUp, serverUp, err := spliceTestSocketPair("tcp")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -222,21 +223,63 @@ func testSpliceReaderAtEOF(t *testing.T) {
|
|||
defer clientDown.Close()
|
||||
defer serverDown.Close()
|
||||
|
||||
serverUp.Close()
|
||||
_, err, handled := splice(serverDown.(*TCPConn).fd, serverUp)
|
||||
if !handled {
|
||||
t.Errorf("closed connection: got err = %v, handled = %t, want handled = true", err, handled)
|
||||
}
|
||||
lr := &io.LimitedReader{
|
||||
N: 0,
|
||||
R: serverUp,
|
||||
}
|
||||
_, err, handled = splice(serverDown.(*TCPConn).fd, lr)
|
||||
_, err, handled := splice(serverDown.(*TCPConn).fd, lr)
|
||||
if !handled {
|
||||
t.Errorf("exhausted LimitedReader: got err = %v, handled = %t, want handled = true", err, handled)
|
||||
}
|
||||
}
|
||||
|
||||
func testSpliceReaderAtEOF(t *testing.T) {
|
||||
clientUp, serverUp, err := spliceTestSocketPair("tcp")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer clientUp.Close()
|
||||
clientDown, serverDown, err := spliceTestSocketPair("tcp")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer clientDown.Close()
|
||||
|
||||
serverUp.Close()
|
||||
|
||||
// We'd like to call net.splice here and check the handled return
|
||||
// value, but we disable splice on old Linux kernels.
|
||||
//
|
||||
// In that case, poll.Splice and net.splice return a non-nil error
|
||||
// and handled == false. We'd ideally like to see handled == true
|
||||
// because the source reader is at EOF, but if we're running on an old
|
||||
// kernel, and splice is disabled, we won't see EOF from net.splice,
|
||||
// because we won't touch the reader at all.
|
||||
//
|
||||
// Trying to untangle the errors from net.splice and match them
|
||||
// against the errors created by the poll package would be brittle,
|
||||
// so this is a higher level test.
|
||||
//
|
||||
// The following ReadFrom should return immediately, regardless of
|
||||
// whether splice is disabled or not. The other side should then
|
||||
// get a goodbye signal. Test for the goodbye signal.
|
||||
msg := "bye"
|
||||
go func() {
|
||||
serverDown.(*TCPConn).ReadFrom(serverUp)
|
||||
io.WriteString(serverDown, msg)
|
||||
serverDown.Close()
|
||||
}()
|
||||
|
||||
buf := make([]byte, 3)
|
||||
_, err = io.ReadFull(clientDown, buf)
|
||||
if err != nil {
|
||||
t.Errorf("clientDown: %v", err)
|
||||
}
|
||||
if string(buf) != msg {
|
||||
t.Errorf("clientDown got %q, want %q", buf, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func testSpliceIssue25985(t *testing.T) {
|
||||
front, err := newLocalListener("tcp")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -5844,7 +5844,7 @@ func clobber() {
|
|||
type funcLayoutTest struct {
|
||||
rcvr, t Type
|
||||
size, argsize, retOffset uintptr
|
||||
stack []byte // pointer bitmap: 1 is pointer, 0 is scalar (or uninitialized)
|
||||
stack []byte // pointer bitmap: 1 is pointer, 0 is scalar
|
||||
gc []byte
|
||||
}
|
||||
|
||||
|
|
@ -5866,7 +5866,7 @@ func init() {
|
|||
6 * PtrSize,
|
||||
4 * PtrSize,
|
||||
4 * PtrSize,
|
||||
[]byte{1, 0, 1},
|
||||
[]byte{1, 0, 1, 0, 1},
|
||||
[]byte{1, 0, 1, 0, 1},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No argsize here, gc generates argsize info at call site.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
NO_LOCAL_POINTERS
|
||||
MOVL DX, 0(SP)
|
||||
LEAL argframe+0(FP), CX
|
||||
MOVL CX, 4(SP)
|
||||
MOVB $0, 12(SP)
|
||||
LEAL 12(SP), AX
|
||||
MOVL AX, 8(SP)
|
||||
CALL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No argsize here, gc generates argsize info at call site.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
NO_LOCAL_POINTERS
|
||||
MOVL DX, 0(SP)
|
||||
LEAL argframe+0(FP), CX
|
||||
MOVL CX, 4(SP)
|
||||
MOVB $0, 12(SP)
|
||||
LEAL 12(SP), AX
|
||||
MOVL AX, 8(SP)
|
||||
CALL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
MOVQ DX, 0(SP)
|
||||
LEAQ argframe+0(FP), CX
|
||||
MOVQ CX, 8(SP)
|
||||
MOVB $0, 24(SP)
|
||||
LEAQ 24(SP), AX
|
||||
MOVQ AX, 16(SP)
|
||||
CALL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
MOVQ DX, 0(SP)
|
||||
LEAQ argframe+0(FP), CX
|
||||
MOVQ CX, 8(SP)
|
||||
MOVB $0, 24(SP)
|
||||
LEAQ 24(SP), AX
|
||||
MOVQ AX, 16(SP)
|
||||
CALL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No argsize here, gc generates argsize info at call site.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
NO_LOCAL_POINTERS
|
||||
MOVL DX, 0(SP)
|
||||
LEAL argframe+0(FP), CX
|
||||
MOVL CX, 4(SP)
|
||||
MOVB $0, 12(SP)
|
||||
LEAL 12(SP), AX
|
||||
MOVL AX, 8(SP)
|
||||
CALL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No argsize here, gc generates argsize info at call site.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
NO_LOCAL_POINTERS
|
||||
MOVL DX, 0(SP)
|
||||
LEAL argframe+0(FP), CX
|
||||
MOVL CX, 4(SP)
|
||||
MOVB $0, 12(SP)
|
||||
LEAL 12(SP), AX
|
||||
MOVL AX, 8(SP)
|
||||
CALL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -9,11 +9,15 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No argsize here, gc generates argsize info at call site.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW R7, 4(R13)
|
||||
MOVW $argframe+0(FP), R1
|
||||
MOVW R1, 8(R13)
|
||||
MOVW $0, R1
|
||||
MOVB R1, 16(R13)
|
||||
ADD $16, R13, R1
|
||||
MOVW R1, 12(R13)
|
||||
BL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -21,10 +25,14 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No argsize here, gc generates argsize info at call site.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW R7, 4(R13)
|
||||
MOVW $argframe+0(FP), R1
|
||||
MOVW R1, 8(R13)
|
||||
MOVW $0, R1
|
||||
MOVB R1, 16(R13)
|
||||
ADD $16, R13, R1
|
||||
MOVW R1, 12(R13)
|
||||
BL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here, runtime pulls arg map out of the func value.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$24
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$40
|
||||
NO_LOCAL_POINTERS
|
||||
MOVD R26, 8(RSP)
|
||||
MOVD $argframe+0(FP), R3
|
||||
MOVD R3, 16(RSP)
|
||||
MOVB $0, 32(RSP)
|
||||
ADD $32, RSP, R3
|
||||
MOVD R3, 24(RSP)
|
||||
BL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$24
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$24
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$40
|
||||
NO_LOCAL_POINTERS
|
||||
MOVD R26, 8(RSP)
|
||||
MOVD $argframe+0(FP), R3
|
||||
MOVD R3, 16(RSP)
|
||||
MOVB $0, 32(RSP)
|
||||
ADD $32, RSP, R3
|
||||
MOVD R3, 24(RSP)
|
||||
BL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -13,11 +13,14 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here, runtime pulls arg map out of the func value.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
MOVV REGCTXT, 8(R29)
|
||||
MOVV $argframe+0(FP), R1
|
||||
MOVV R1, 16(R29)
|
||||
MOVB R0, 32(R29)
|
||||
ADDV $32, R29, R1
|
||||
MOVV R1, 24(R29)
|
||||
JAL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -25,10 +28,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
MOVV REGCTXT, 8(R29)
|
||||
MOVV $argframe+0(FP), R1
|
||||
MOVV R1, 16(R29)
|
||||
MOVB R0, 32(R29)
|
||||
ADDV $32, R29, R1
|
||||
MOVV R1, 24(R29)
|
||||
JAL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -13,11 +13,14 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here, runtime pulls arg map out of the func value.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW REGCTXT, 4(R29)
|
||||
MOVW $argframe+0(FP), R1
|
||||
MOVW R1, 8(R29)
|
||||
MOVB R0, 16(R29)
|
||||
ADD $16, R29, R1
|
||||
MOVW R1, 12(R29)
|
||||
JAL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -25,10 +28,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW REGCTXT, 4(R29)
|
||||
MOVW $argframe+0(FP), R1
|
||||
MOVW R1, 8(R29)
|
||||
MOVB R0, 16(R29)
|
||||
ADD $16, R29, R1
|
||||
MOVW R1, 12(R29)
|
||||
JAL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -12,11 +12,14 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here, runtime pulls arg map out of the func value.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
MOVD R11, FIXED_FRAME+0(R1)
|
||||
MOVD $argframe+0(FP), R3
|
||||
MOVD R3, FIXED_FRAME+8(R1)
|
||||
MOVB R0, FIXED_FRAME+24(R1)
|
||||
ADD $FIXED_FRAME+24, R1, R3
|
||||
MOVD R3, FIXED_FRAME+16(R1)
|
||||
BL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -24,10 +27,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
MOVD R11, FIXED_FRAME+0(R1)
|
||||
MOVD $argframe+0(FP), R3
|
||||
MOVD R3, FIXED_FRAME+8(R1)
|
||||
MOVB R0, FIXED_FRAME+24(R1)
|
||||
ADD $FIXED_FRAME+24, R1, R3
|
||||
MOVD R3, FIXED_FRAME+16(R1)
|
||||
BL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here, runtime pulls arg map out of the func value.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
MOVD R12, 8(R15)
|
||||
MOVD $argframe+0(FP), R3
|
||||
MOVD R3, 16(R15)
|
||||
MOVB $0, 32(R15)
|
||||
ADD $32, R15, R3
|
||||
MOVD R3, 24(R15)
|
||||
BL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -21,10 +24,13 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
MOVD R12, 8(R15)
|
||||
MOVD $argframe+0(FP), R3
|
||||
MOVD R3, 16(R15)
|
||||
MOVB $0, 32(R15)
|
||||
ADD $32, R15, R3
|
||||
MOVD R3, 24(R15)
|
||||
BL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// See the comment on the declaration of makeFuncStub in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
|
||||
MOVD CTXT, 0(SP)
|
||||
|
|
@ -21,6 +21,9 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
|||
I64Add
|
||||
I64Store $8
|
||||
|
||||
MOVB $0, 24(SP)
|
||||
MOVD $24(SP), 16(SP)
|
||||
|
||||
CALL ·callReflect(SB)
|
||||
RET
|
||||
|
||||
|
|
@ -28,7 +31,7 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
|
|||
// See the comment on the declaration of methodValueCall in makefunc.go
|
||||
// for more details.
|
||||
// No arg size here; runtime pulls arg map out of the func value.
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
||||
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$32
|
||||
NO_LOCAL_POINTERS
|
||||
|
||||
MOVD CTXT, 0(SP)
|
||||
|
|
@ -40,5 +43,8 @@ TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
|
|||
I64Add
|
||||
I64Store $8
|
||||
|
||||
MOVB $0, 24(SP)
|
||||
MOVD $24(SP), 16(SP)
|
||||
|
||||
CALL ·callMethod(SB)
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr,
|
|||
var ft *rtype
|
||||
var s *bitVector
|
||||
if rcvr != nil {
|
||||
ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), rcvr.(*rtype))
|
||||
ft, argSize, retOffset, s, _ = funcLayout((*funcType)(unsafe.Pointer(t.(*rtype))), rcvr.(*rtype))
|
||||
} else {
|
||||
ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil)
|
||||
ft, argSize, retOffset, s, _ = funcLayout((*funcType)(unsafe.Pointer(t.(*rtype))), nil)
|
||||
}
|
||||
frametype = ft
|
||||
for i := uint32(0); i < s.n; i++ {
|
||||
|
|
|
|||
|
|
@ -12,14 +12,15 @@ import (
|
|||
|
||||
// makeFuncImpl is the closure value implementing the function
|
||||
// returned by MakeFunc.
|
||||
// The first two words of this type must be kept in sync with
|
||||
// The first three words of this type must be kept in sync with
|
||||
// methodValue and runtime.reflectMethodValue.
|
||||
// Any changes should be reflected in all three.
|
||||
type makeFuncImpl struct {
|
||||
code uintptr
|
||||
stack *bitVector
|
||||
typ *funcType
|
||||
fn func([]Value) []Value
|
||||
code uintptr
|
||||
stack *bitVector // ptrmap for both args and results
|
||||
argLen uintptr // just args
|
||||
ftyp *funcType
|
||||
fn func([]Value) []Value
|
||||
}
|
||||
|
||||
// MakeFunc returns a new function of the given Type
|
||||
|
|
@ -59,9 +60,9 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
|
|||
code := **(**uintptr)(unsafe.Pointer(&dummy))
|
||||
|
||||
// makeFuncImpl contains a stack map for use by the runtime
|
||||
_, _, _, stack, _ := funcLayout(t, nil)
|
||||
_, argLen, _, stack, _ := funcLayout(ftyp, nil)
|
||||
|
||||
impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
|
||||
impl := &makeFuncImpl{code: code, stack: stack, argLen: argLen, ftyp: ftyp, fn: fn}
|
||||
|
||||
return Value{t, unsafe.Pointer(impl), flag(Func)}
|
||||
}
|
||||
|
|
@ -73,12 +74,13 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
|
|||
// word in the passed-in argument frame.
|
||||
func makeFuncStub()
|
||||
|
||||
// The first two words of this type must be kept in sync with
|
||||
// The first 3 words of this type must be kept in sync with
|
||||
// makeFuncImpl and runtime.reflectMethodValue.
|
||||
// Any changes should be reflected in all three.
|
||||
type methodValue struct {
|
||||
fn uintptr
|
||||
stack *bitVector
|
||||
stack *bitVector // ptrmap for both args and results
|
||||
argLen uintptr // just args
|
||||
method int
|
||||
rcvr Value
|
||||
}
|
||||
|
|
@ -101,7 +103,7 @@ func makeMethodValue(op string, v Value) Value {
|
|||
rcvr := Value{v.typ, v.ptr, fl}
|
||||
|
||||
// v.Type returns the actual type of the method value.
|
||||
funcType := v.Type().(*rtype)
|
||||
ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype)))
|
||||
|
||||
// Indirect Go func value (dummy) to obtain
|
||||
// actual code address. (A Go func value is a pointer
|
||||
|
|
@ -110,11 +112,12 @@ func makeMethodValue(op string, v Value) Value {
|
|||
code := **(**uintptr)(unsafe.Pointer(&dummy))
|
||||
|
||||
// methodValue contains a stack map for use by the runtime
|
||||
_, _, _, stack, _ := funcLayout(funcType, nil)
|
||||
_, argLen, _, stack, _ := funcLayout(ftyp, nil)
|
||||
|
||||
fv := &methodValue{
|
||||
fn: code,
|
||||
stack: stack,
|
||||
argLen: argLen,
|
||||
method: int(v.flag) >> flagMethodShift,
|
||||
rcvr: rcvr,
|
||||
}
|
||||
|
|
@ -124,7 +127,7 @@ func makeMethodValue(op string, v Value) Value {
|
|||
// but we want Interface() and other operations to fail early.
|
||||
methodReceiver(op, fv.rcvr, fv.method)
|
||||
|
||||
return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
|
||||
return Value{&ftyp.rtype, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
|
||||
}
|
||||
|
||||
// methodValueCall is an assembly function that is the code half of
|
||||
|
|
|
|||
|
|
@ -3022,8 +3022,8 @@ func toType(t *rtype) Type {
|
|||
}
|
||||
|
||||
type layoutKey struct {
|
||||
t *rtype // function signature
|
||||
rcvr *rtype // receiver type, or nil if none
|
||||
ftyp *funcType // function signature
|
||||
rcvr *rtype // receiver type, or nil if none
|
||||
}
|
||||
|
||||
type layoutType struct {
|
||||
|
|
@ -3042,7 +3042,7 @@ var layoutCache sync.Map // map[layoutKey]layoutType
|
|||
// The returned type exists only for GC, so we only fill out GC relevant info.
|
||||
// Currently, that's just size and the GC program. We also fill in
|
||||
// the name for possible debugging use.
|
||||
func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) {
|
||||
func funcLayout(t *funcType, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) {
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: funcLayout of non-func type")
|
||||
}
|
||||
|
|
@ -3055,8 +3055,6 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
|
|||
return lt.t, lt.argSize, lt.retOffset, lt.stack, lt.framePool
|
||||
}
|
||||
|
||||
tt := (*funcType)(unsafe.Pointer(t))
|
||||
|
||||
// compute gc program & stack bitmap for arguments
|
||||
ptrmap := new(bitVector)
|
||||
var offset uintptr
|
||||
|
|
@ -3066,22 +3064,23 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
|
|||
// space no matter how big they actually are.
|
||||
if ifaceIndir(rcvr) || rcvr.pointers() {
|
||||
ptrmap.append(1)
|
||||
} else {
|
||||
ptrmap.append(0)
|
||||
}
|
||||
offset += ptrSize
|
||||
}
|
||||
for _, arg := range tt.in() {
|
||||
for _, arg := range t.in() {
|
||||
offset += -offset & uintptr(arg.align-1)
|
||||
addTypeBits(ptrmap, offset, arg)
|
||||
offset += arg.size
|
||||
}
|
||||
argN := ptrmap.n
|
||||
argSize = offset
|
||||
if runtime.GOARCH == "amd64p32" {
|
||||
offset += -offset & (8 - 1)
|
||||
}
|
||||
offset += -offset & (ptrSize - 1)
|
||||
retOffset = offset
|
||||
for _, res := range tt.out() {
|
||||
for _, res := range t.out() {
|
||||
offset += -offset & uintptr(res.align-1)
|
||||
addTypeBits(ptrmap, offset, res)
|
||||
offset += res.size
|
||||
|
|
@ -3102,7 +3101,6 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
|
|||
} else {
|
||||
x.kind |= kindNoPointers
|
||||
}
|
||||
ptrmap.n = argN
|
||||
|
||||
var s string
|
||||
if rcvr != nil {
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ var callGC bool // for testing; see TestCallMethodJump
|
|||
|
||||
func (v Value) call(op string, in []Value) []Value {
|
||||
// Get function pointer, type.
|
||||
t := v.typ
|
||||
t := (*funcType)(unsafe.Pointer(v.typ))
|
||||
var (
|
||||
fn unsafe.Pointer
|
||||
rcvr Value
|
||||
|
|
@ -453,15 +453,14 @@ func (v Value) call(op string, in []Value) []Value {
|
|||
|
||||
var ret []Value
|
||||
if nout == 0 {
|
||||
// This is untyped because the frame is really a
|
||||
// stack, even though it's a heap object.
|
||||
memclrNoHeapPointers(args, frametype.size)
|
||||
typedmemclr(frametype, args)
|
||||
framePool.Put(args)
|
||||
} else {
|
||||
// Zero the now unused input area of args,
|
||||
// because the Values returned by this function contain pointers to the args object,
|
||||
// and will thus keep the args object alive indefinitely.
|
||||
memclrNoHeapPointers(args, retOffset)
|
||||
typedmemclrpartial(frametype, args, 0, retOffset)
|
||||
|
||||
// Wrap Values around return values in args.
|
||||
ret = make([]Value, nout)
|
||||
off = retOffset
|
||||
|
|
@ -472,6 +471,10 @@ func (v Value) call(op string, in []Value) []Value {
|
|||
if tv.Size() != 0 {
|
||||
fl := flagIndir | flag(tv.Kind())
|
||||
ret[i] = Value{tv.common(), add(args, off, "tv.Size() != 0"), fl}
|
||||
// Note: this does introduce false sharing between results -
|
||||
// if any result is live, they are all live.
|
||||
// (And the space for the args is live as well, but as we've
|
||||
// cleared that space it isn't as big a deal.)
|
||||
} else {
|
||||
// For zero-sized return value, args+off may point to the next object.
|
||||
// In this case, return the zero value instead.
|
||||
|
|
@ -496,8 +499,13 @@ func (v Value) call(op string, in []Value) []Value {
|
|||
// NOTE: This function must be marked as a "wrapper" in the generated code,
|
||||
// so that the linker can make it work correctly for panic and recover.
|
||||
// The gc compilers know to do that for the name "reflect.callReflect".
|
||||
func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
|
||||
ftyp := ctxt.typ
|
||||
//
|
||||
// ctxt is the "closure" generated by MakeFunc.
|
||||
// frame is a pointer to the arguments to that closure on the stack.
|
||||
// retValid points to a boolean which should be set when the results
|
||||
// section of frame is set.
|
||||
func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
|
||||
ftyp := ctxt.ftyp
|
||||
f := ctxt.fn
|
||||
|
||||
// Copy argument frame into Values.
|
||||
|
|
@ -562,6 +570,16 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
|
|||
}
|
||||
}
|
||||
|
||||
// Announce that the return values are valid.
|
||||
// After this point the runtime can depend on the return values being valid.
|
||||
*retValid = true
|
||||
|
||||
// We have to make sure that the out slice lives at least until
|
||||
// the runtime knows the return values are valid. Otherwise, the
|
||||
// return values might not be scanned by anyone during a GC.
|
||||
// (out would be dead, and the return slots not yet alive.)
|
||||
runtime.KeepAlive(out)
|
||||
|
||||
// runtime.getArgInfo expects to be able to find ctxt on the
|
||||
// stack when it finds our caller, makeFuncStub. Make sure it
|
||||
// doesn't get garbage collected.
|
||||
|
|
@ -575,7 +593,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
|
|||
// The return value rcvrtype gives the method's actual receiver type.
|
||||
// The return value t gives the method type signature (without the receiver).
|
||||
// The return value fn is a pointer to the method code.
|
||||
func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) {
|
||||
func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *rtype, t *funcType, fn unsafe.Pointer) {
|
||||
i := methodIndex
|
||||
if v.typ.Kind() == Interface {
|
||||
tt := (*interfaceType)(unsafe.Pointer(v.typ))
|
||||
|
|
@ -592,7 +610,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
|
|||
}
|
||||
rcvrtype = iface.itab.typ
|
||||
fn = unsafe.Pointer(&iface.itab.fun[i])
|
||||
t = tt.typeOff(m.typ)
|
||||
t = (*funcType)(unsafe.Pointer(tt.typeOff(m.typ)))
|
||||
} else {
|
||||
rcvrtype = v.typ
|
||||
ms := v.typ.exportedMethods()
|
||||
|
|
@ -605,7 +623,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
|
|||
}
|
||||
ifn := v.typ.textOff(m.ifn)
|
||||
fn = unsafe.Pointer(&ifn)
|
||||
t = v.typ.typeOff(m.mtyp)
|
||||
t = (*funcType)(unsafe.Pointer(v.typ.typeOff(m.mtyp)))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -644,23 +662,31 @@ func align(x, n uintptr) uintptr {
|
|||
// NOTE: This function must be marked as a "wrapper" in the generated code,
|
||||
// so that the linker can make it work correctly for panic and recover.
|
||||
// The gc compilers know to do that for the name "reflect.callMethod".
|
||||
func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
|
||||
//
|
||||
// ctxt is the "closure" generated by makeVethodValue.
|
||||
// frame is a pointer to the arguments to that closure on the stack.
|
||||
// retValid points to a boolean which should be set when the results
|
||||
// section of frame is set.
|
||||
func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool) {
|
||||
rcvr := ctxt.rcvr
|
||||
rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
|
||||
frametype, argSize, retOffset, _, framePool := funcLayout(t, rcvrtype)
|
||||
|
||||
// Make a new frame that is one word bigger so we can store the receiver.
|
||||
args := framePool.Get().(unsafe.Pointer)
|
||||
// This space is used for both arguments and return values.
|
||||
scratch := framePool.Get().(unsafe.Pointer)
|
||||
|
||||
// Copy in receiver and rest of args.
|
||||
// Avoid constructing out-of-bounds pointers if there are no args.
|
||||
storeRcvr(rcvr, args)
|
||||
storeRcvr(rcvr, scratch)
|
||||
if argSize-ptrSize > 0 {
|
||||
typedmemmovepartial(frametype, add(args, ptrSize, "argSize > ptrSize"), frame, ptrSize, argSize-ptrSize)
|
||||
typedmemmovepartial(frametype, add(scratch, ptrSize, "argSize > ptrSize"), frame, ptrSize, argSize-ptrSize)
|
||||
}
|
||||
|
||||
// Call.
|
||||
call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
|
||||
// Call copies the arguments from scratch to the stack, calls fn,
|
||||
// and then copies the results back into scratch.
|
||||
call(frametype, fn, scratch, uint32(frametype.size), uint32(retOffset))
|
||||
|
||||
// Copy return values. On amd64p32, the beginning of return values
|
||||
// is 64-bit aligned, so the caller's frame layout (which doesn't have
|
||||
|
|
@ -673,17 +699,21 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
|
|||
if runtime.GOARCH == "amd64p32" {
|
||||
callerRetOffset = align(argSize-ptrSize, 8)
|
||||
}
|
||||
typedmemmovepartial(frametype,
|
||||
add(frame, callerRetOffset, "frametype.size > retOffset"),
|
||||
add(args, retOffset, "frametype.size > retOffset"),
|
||||
retOffset,
|
||||
// This copies to the stack. Write barriers are not needed.
|
||||
memmove(add(frame, callerRetOffset, "frametype.size > retOffset"),
|
||||
add(scratch, retOffset, "frametype.size > retOffset"),
|
||||
frametype.size-retOffset)
|
||||
}
|
||||
|
||||
// This is untyped because the frame is really a stack, even
|
||||
// though it's a heap object.
|
||||
memclrNoHeapPointers(args, frametype.size)
|
||||
framePool.Put(args)
|
||||
// Tell the runtime it can now depend on the return values
|
||||
// being properly initialized.
|
||||
*retValid = true
|
||||
|
||||
// Clear the scratch space and put it back in the pool.
|
||||
// This must happen after the statement above, so that the return
|
||||
// values will always be scanned by someone.
|
||||
typedmemclr(frametype, scratch)
|
||||
framePool.Put(scratch)
|
||||
|
||||
// See the comment in callReflect.
|
||||
runtime.KeepAlive(ctxt)
|
||||
|
|
@ -2569,6 +2599,10 @@ func call(argtype *rtype, fn, arg unsafe.Pointer, n uint32, retoffset uint32)
|
|||
|
||||
func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
|
||||
|
||||
// memmove copies size bytes to dst from src. No write barriers are used.
|
||||
//go:noescape
|
||||
func memmove(dst, src unsafe.Pointer, size uintptr)
|
||||
|
||||
// typedmemmove copies a value of type t to dst from src.
|
||||
//go:noescape
|
||||
func typedmemmove(t *rtype, dst, src unsafe.Pointer)
|
||||
|
|
@ -2578,14 +2612,20 @@ func typedmemmove(t *rtype, dst, src unsafe.Pointer)
|
|||
//go:noescape
|
||||
func typedmemmovepartial(t *rtype, dst, src unsafe.Pointer, off, size uintptr)
|
||||
|
||||
// typedmemclr zeros the value at ptr of type t.
|
||||
//go:noescape
|
||||
func typedmemclr(t *rtype, ptr unsafe.Pointer)
|
||||
|
||||
// typedmemclrpartial is like typedmemclr but assumes that
|
||||
// dst points off bytes into the value and only clears size bytes.
|
||||
//go:noescape
|
||||
func typedmemclrpartial(t *rtype, ptr unsafe.Pointer, off, size uintptr)
|
||||
|
||||
// typedslicecopy copies a slice of elemType values from src to dst,
|
||||
// returning the number of elements copied.
|
||||
//go:noescape
|
||||
func typedslicecopy(elemType *rtype, dst, src sliceHeader) int
|
||||
|
||||
//go:noescape
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
// Dummy annotation marking that the value x escapes,
|
||||
// for use in cases where the reflect code is so clever that
|
||||
// the compiler cannot follow.
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ func makechan(t *chantype, size int) *hchan {
|
|||
// Queue or element size is zero.
|
||||
c = (*hchan)(mallocgc(hchanSize, nil, true))
|
||||
// Race detector uses this location for synchronization.
|
||||
c.buf = unsafe.Pointer(c)
|
||||
c.buf = c.raceaddr()
|
||||
case elem.kind&kindNoPointers != 0:
|
||||
// Elements do not contain pointers.
|
||||
// Allocate hchan and buf in one call.
|
||||
|
|
@ -151,7 +151,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
|
|||
}
|
||||
|
||||
if raceenabled {
|
||||
racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend))
|
||||
racereadpc(c.raceaddr(), callerpc, funcPC(chansend))
|
||||
}
|
||||
|
||||
// Fast path: check for failed non-blocking operation without acquiring the lock.
|
||||
|
|
@ -337,8 +337,8 @@ func closechan(c *hchan) {
|
|||
|
||||
if raceenabled {
|
||||
callerpc := getcallerpc()
|
||||
racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan))
|
||||
racerelease(unsafe.Pointer(c))
|
||||
racewritepc(c.raceaddr(), callerpc, funcPC(closechan))
|
||||
racerelease(c.raceaddr())
|
||||
}
|
||||
|
||||
c.closed = 1
|
||||
|
|
@ -361,7 +361,7 @@ func closechan(c *hchan) {
|
|||
gp := sg.g
|
||||
gp.param = nil
|
||||
if raceenabled {
|
||||
raceacquireg(gp, unsafe.Pointer(c))
|
||||
raceacquireg(gp, c.raceaddr())
|
||||
}
|
||||
gp.schedlink.set(glist)
|
||||
glist = gp
|
||||
|
|
@ -380,7 +380,7 @@ func closechan(c *hchan) {
|
|||
gp := sg.g
|
||||
gp.param = nil
|
||||
if raceenabled {
|
||||
raceacquireg(gp, unsafe.Pointer(c))
|
||||
raceacquireg(gp, c.raceaddr())
|
||||
}
|
||||
gp.schedlink.set(glist)
|
||||
glist = gp
|
||||
|
|
@ -457,7 +457,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
|
|||
|
||||
if c.closed != 0 && c.qcount == 0 {
|
||||
if raceenabled {
|
||||
raceacquire(unsafe.Pointer(c))
|
||||
raceacquire(c.raceaddr())
|
||||
}
|
||||
unlock(&c.lock)
|
||||
if ep != nil {
|
||||
|
|
@ -735,6 +735,15 @@ func (q *waitq) dequeue() *sudog {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *hchan) raceaddr() unsafe.Pointer {
|
||||
// Treat read-like and write-like operations on the channel to
|
||||
// happen at this address. Avoid using the address of qcount
|
||||
// or dataqsiz, because the len() and cap() builtins read
|
||||
// those addresses, and we don't want them racing with
|
||||
// operations like close().
|
||||
return unsafe.Pointer(&c.buf)
|
||||
}
|
||||
|
||||
func racesync(c *hchan, sg *sudog) {
|
||||
racerelease(chanbuf(c, 0))
|
||||
raceacquireg(sg.g, chanbuf(c, 0))
|
||||
|
|
|
|||
|
|
@ -320,6 +320,19 @@ func typedmemclr(typ *_type, ptr unsafe.Pointer) {
|
|||
memclrNoHeapPointers(ptr, typ.size)
|
||||
}
|
||||
|
||||
//go:linkname reflect_typedmemclr reflect.typedmemclr
|
||||
func reflect_typedmemclr(typ *_type, ptr unsafe.Pointer) {
|
||||
typedmemclr(typ, ptr)
|
||||
}
|
||||
|
||||
//go:linkname reflect_typedmemclrpartial reflect.typedmemclrpartial
|
||||
func reflect_typedmemclrpartial(typ *_type, ptr unsafe.Pointer, off, size uintptr) {
|
||||
if typ.kind&kindNoPointers == 0 {
|
||||
bulkBarrierPreWrite(uintptr(ptr), 0, size)
|
||||
}
|
||||
memclrNoHeapPointers(ptr, size)
|
||||
}
|
||||
|
||||
// memclrHasPointers clears n bytes of typed memory starting at ptr.
|
||||
// The caller must ensure that the type of the object at ptr has
|
||||
// pointers, usually by checking typ.kind&kindNoPointers. However, ptr
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ func semacreate(mp *m) {
|
|||
|
||||
//go:nosplit
|
||||
func semasleep(ns int64) int32 {
|
||||
var start int64
|
||||
if ns >= 0 {
|
||||
start = nanotime()
|
||||
}
|
||||
mp := getg().m
|
||||
pthread_mutex_lock(&mp.mutex)
|
||||
for {
|
||||
|
|
@ -43,8 +47,13 @@ func semasleep(ns int64) int32 {
|
|||
return 0
|
||||
}
|
||||
if ns >= 0 {
|
||||
spent := nanotime() - start
|
||||
if spent >= ns {
|
||||
pthread_mutex_unlock(&mp.mutex)
|
||||
return -1
|
||||
}
|
||||
var t timespec
|
||||
t.set_nsec(ns)
|
||||
t.set_nsec(ns - spent)
|
||||
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
|
||||
if err == _ETIMEDOUT {
|
||||
pthread_mutex_unlock(&mp.mutex)
|
||||
|
|
|
|||
|
|
@ -197,23 +197,23 @@ func semacreate(mp *m) {
|
|||
//go:nosplit
|
||||
func semasleep(ns int64) int32 {
|
||||
var ret int32
|
||||
|
||||
systemstack(func() {
|
||||
_g_ := getg()
|
||||
if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
|
||||
throw("semasleep")
|
||||
}
|
||||
|
||||
var ts timespec
|
||||
if ns >= 0 {
|
||||
end := ns + nanotime()
|
||||
ts.tv_sec = end / 1e9
|
||||
ts.tv_nsec = int32(end % 1e9)
|
||||
}
|
||||
for _g_.m.waitsemacount == 0 {
|
||||
if ns < 0 {
|
||||
if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
|
||||
throw("semasleep")
|
||||
}
|
||||
} else {
|
||||
var ts timespec
|
||||
end := ns + nanotime()
|
||||
ts.tv_sec = end / 1e9
|
||||
ts.tv_nsec = int32(end % 1e9)
|
||||
r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
|
||||
if r == -_ETIMEDOUT {
|
||||
nacl_mutex_unlock(_g_.m.waitsemalock)
|
||||
|
|
|
|||
|
|
@ -126,15 +126,9 @@ func semacreate(mp *m) {
|
|||
//go:nosplit
|
||||
func semasleep(ns int64) int32 {
|
||||
_g_ := getg()
|
||||
|
||||
// Compute sleep deadline.
|
||||
var tsp *timespec
|
||||
var ts timespec
|
||||
var deadline int64
|
||||
if ns >= 0 {
|
||||
var nsec int32
|
||||
ts.set_sec(timediv(ns, 1000000000, &nsec))
|
||||
ts.set_nsec(nsec)
|
||||
tsp = &ts
|
||||
deadline = nanotime() + ns
|
||||
}
|
||||
|
||||
for {
|
||||
|
|
@ -147,18 +141,21 @@ func semasleep(ns int64) int32 {
|
|||
}
|
||||
|
||||
// Sleep until unparked by semawakeup or timeout.
|
||||
var tsp *timespec
|
||||
var ts timespec
|
||||
if ns >= 0 {
|
||||
wait := deadline - nanotime()
|
||||
if wait <= 0 {
|
||||
return -1
|
||||
}
|
||||
var nsec int32
|
||||
ts.set_sec(timediv(wait, 1000000000, &nsec))
|
||||
ts.set_nsec(nsec)
|
||||
tsp = &ts
|
||||
}
|
||||
ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
|
||||
if ret == _ETIMEDOUT {
|
||||
return -1
|
||||
} else if ret == _EINTR && ns >= 0 {
|
||||
// Avoid sleeping forever if we keep getting
|
||||
// interrupted (for example by the profiling
|
||||
// timer). It would be if tsp upon return had the
|
||||
// remaining time to sleep, but this is good enough.
|
||||
var nsec int32
|
||||
ns /= 2
|
||||
ts.set_sec(timediv(ns, 1000000000, &nsec))
|
||||
ts.set_nsec(nsec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -577,18 +577,32 @@ func TestRaceChanItselfCap(t *testing.T) {
|
|||
<-compl
|
||||
}
|
||||
|
||||
func TestRaceChanCloseLen(t *testing.T) {
|
||||
v := 0
|
||||
_ = v
|
||||
func TestNoRaceChanCloseLen(t *testing.T) {
|
||||
c := make(chan int, 10)
|
||||
c <- 0
|
||||
r := make(chan int, 10)
|
||||
go func() {
|
||||
v = 1
|
||||
close(c)
|
||||
r <- len(c)
|
||||
}()
|
||||
time.Sleep(1e7)
|
||||
_ = len(c)
|
||||
v = 2
|
||||
go func() {
|
||||
close(c)
|
||||
r <- 0
|
||||
}()
|
||||
<-r
|
||||
<-r
|
||||
}
|
||||
|
||||
func TestNoRaceChanCloseCap(t *testing.T) {
|
||||
c := make(chan int, 10)
|
||||
r := make(chan int, 10)
|
||||
go func() {
|
||||
r <- cap(c)
|
||||
}()
|
||||
go func() {
|
||||
close(c)
|
||||
r <- 0
|
||||
}()
|
||||
<-r
|
||||
<-r
|
||||
}
|
||||
|
||||
func TestRaceChanCloseSend(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ loop:
|
|||
|
||||
case caseSend:
|
||||
if raceenabled {
|
||||
racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
|
||||
racereadpc(c.raceaddr(), cas.pc, chansendpc)
|
||||
}
|
||||
if c.closed != 0 {
|
||||
goto sclose
|
||||
|
|
@ -462,7 +462,7 @@ rclose:
|
|||
typedmemclr(c.elemtype, cas.elem)
|
||||
}
|
||||
if raceenabled {
|
||||
raceacquire(unsafe.Pointer(c))
|
||||
raceacquire(c.raceaddr())
|
||||
}
|
||||
goto retc
|
||||
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ type traceContextKey struct{}
|
|||
// If the end function is called multiple times, only the first
|
||||
// call is used in the latency measurement.
|
||||
//
|
||||
// ctx, task := trace.NewTask(ctx, "awesome task")
|
||||
// trace.WithRegion(ctx, prepWork)
|
||||
// ctx, task := trace.NewTask(ctx, "awesomeTask")
|
||||
// trace.WithRegion(ctx, "preparation", prepWork)
|
||||
// // preparation of the task
|
||||
// go func() { // continue processing the task in a separate goroutine.
|
||||
// defer task.End()
|
||||
// trace.WithRegion(ctx, remainingWork)
|
||||
// }
|
||||
// trace.WithRegion(ctx, "remainingWork", remainingWork)
|
||||
// }()
|
||||
func NewTask(pctx context.Context, taskType string) (ctx context.Context, task *Task) {
|
||||
pid := fromContext(pctx).id
|
||||
id := newID()
|
||||
|
|
|
|||
|
|
@ -557,8 +557,9 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
|||
// reflectMethodValue is a partial duplicate of reflect.makeFuncImpl
|
||||
// and reflect.methodValue.
|
||||
type reflectMethodValue struct {
|
||||
fn uintptr
|
||||
stack *bitvector // args bitmap
|
||||
fn uintptr
|
||||
stack *bitvector // ptrmap for both args and results
|
||||
argLen uintptr // just args
|
||||
}
|
||||
|
||||
// getArgInfoFast returns the argument frame information for a call to f.
|
||||
|
|
@ -587,6 +588,7 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
|
|||
// These take a *reflect.methodValue as their
|
||||
// context register.
|
||||
var mv *reflectMethodValue
|
||||
var retValid bool
|
||||
if ctxt != nil {
|
||||
// This is not an actual call, but a
|
||||
// deferred call. The function value
|
||||
|
|
@ -600,6 +602,10 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
|
|||
// 0(SP).
|
||||
arg0 := frame.sp + sys.MinFrameSize
|
||||
mv = *(**reflectMethodValue)(unsafe.Pointer(arg0))
|
||||
// Figure out whether the return values are valid.
|
||||
// Reflect will update this value after it copies
|
||||
// in the return values.
|
||||
retValid = *(*bool)(unsafe.Pointer(arg0 + 3*sys.PtrSize))
|
||||
}
|
||||
if mv.fn != f.entry {
|
||||
print("runtime: confused by ", funcname(f), "\n")
|
||||
|
|
@ -607,6 +613,9 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
|
|||
}
|
||||
bv := mv.stack
|
||||
arglen = uintptr(bv.n * sys.PtrSize)
|
||||
if !retValid {
|
||||
arglen = uintptr(mv.argLen) &^ (sys.PtrSize - 1)
|
||||
}
|
||||
argmap = bv
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
// compile
|
||||
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Issue 27143: cmd/compile: erroneous application of walkinrange
|
||||
// optimization for const over 2**63
|
||||
|
||||
package p
|
||||
|
||||
var c uint64
|
||||
|
||||
var b1 bool = 0x7fffffffffffffff < c && c < 0x8000000000000000
|
||||
var b2 bool = c < 0x8000000000000000 && 0x7fffffffffffffff < c
|
||||
var b3 bool = 0x8000000000000000 < c && c < 0x8000000000000001
|
||||
var b4 bool = c < 0x8000000000000001 && 0x8000000000000000 < c
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// run
|
||||
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Issue 27278: dead auto elim deletes an auto and its
|
||||
// initialization, but it is live because of a nil check.
|
||||
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
_ [3]string
|
||||
T2
|
||||
}
|
||||
|
||||
func (t *T) M() []string {
|
||||
return t.T2.M()
|
||||
}
|
||||
|
||||
type T2 struct {
|
||||
T3
|
||||
}
|
||||
|
||||
func (t *T2) M() []string {
|
||||
return t.T3.M()
|
||||
}
|
||||
|
||||
type T3 struct {
|
||||
a string
|
||||
}
|
||||
|
||||
func (t *T3) M() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func main() {
|
||||
poison()
|
||||
f()
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f() {
|
||||
(&T{}).M()
|
||||
grow(10000)
|
||||
}
|
||||
|
||||
// grow stack, triggers stack copy
|
||||
func grow(n int) {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
grow(n-1)
|
||||
}
|
||||
|
||||
// put some junk on stack, which cannot be valid address
|
||||
//go:noinline
|
||||
func poison() {
|
||||
x := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
g = x
|
||||
}
|
||||
|
||||
var g [10]int
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// run
|
||||
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Make sure we don't prove that the bounds check failure branch is unreachable.
|
||||
|
||||
package main
|
||||
|
||||
//go:noinline
|
||||
func f(a []int) {
|
||||
_ = a[len(a)-1]
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
return
|
||||
}
|
||||
panic("f should panic")
|
||||
}()
|
||||
f(nil)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// errorcheck
|
||||
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Issue 27356: function parameter hiding built-in function results in compiler crash
|
||||
|
||||
package p
|
||||
|
||||
var a = []int{1,2,3}
|
||||
|
||||
func _(len int) {
|
||||
_ = len(a) // ERROR "cannot call non-function"
|
||||
}
|
||||
|
||||
var cap = false
|
||||
var _ = cap(a) // ERROR "cannot call non-function"
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// run
|
||||
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Make sure return values are always scanned, when
|
||||
// calling methods (+functions, TODO) with reflect.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
debug.SetGCPercent(1) // run GC frequently
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 20; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < 2000; i++ {
|
||||
_test()
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
type Stt struct {
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
type My struct {
|
||||
b byte
|
||||
}
|
||||
|
||||
func (this *My) Run(rawData []byte) (Stt, error) {
|
||||
var data string = "hello"
|
||||
stt := Stt{
|
||||
Data: data,
|
||||
}
|
||||
return stt, nil
|
||||
}
|
||||
|
||||
func _test() (interface{}, error) {
|
||||
f := reflect.ValueOf(&My{}).MethodByName("Run")
|
||||
if method, ok := f.Interface().(func([]byte) (Stt, error)); ok {
|
||||
s, e := method(nil)
|
||||
// The bug in issue27695 happens here, during the return
|
||||
// from the above call (at the end of reflect.callMethod
|
||||
// when preparing to return). The result value that
|
||||
// is assigned to s was not being scanned if GC happens
|
||||
// to occur there.
|
||||
i := interface{}(s)
|
||||
return i, e
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// run
|
||||
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Make sure return values aren't scanned until they
|
||||
// are initialized, when calling functions and methods
|
||||
// via reflect.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var badPtr uintptr
|
||||
|
||||
var sink []byte
|
||||
|
||||
func init() {
|
||||
// Allocate large enough to use largeAlloc.
|
||||
b := make([]byte, 1<<16-1)
|
||||
sink = b // force heap allocation
|
||||
// Any space between the object and the end of page is invalid to point to.
|
||||
badPtr = uintptr(unsafe.Pointer(&b[len(b)-1])) + 1
|
||||
}
|
||||
|
||||
func f(d func() *byte) *byte {
|
||||
// Initialize callee args section with a bad pointer.
|
||||
g(badPtr)
|
||||
|
||||
// Then call a function which returns a pointer.
|
||||
// That return slot starts out holding a bad pointer.
|
||||
return d()
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func g(x uintptr) {
|
||||
}
|
||||
|
||||
type T struct {
|
||||
}
|
||||
|
||||
func (t *T) Foo() *byte {
|
||||
runtime.GC()
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Functions
|
||||
d := reflect.MakeFunc(reflect.TypeOf(func() *byte { return nil }),
|
||||
func(args []reflect.Value) []reflect.Value {
|
||||
runtime.GC()
|
||||
return []reflect.Value{reflect.ValueOf((*byte)(nil))}
|
||||
}).Interface().(func() *byte)
|
||||
f(d)
|
||||
|
||||
// Methods
|
||||
e := reflect.ValueOf(&T{}).Method(0).Interface().(func() *byte)
|
||||
f(e)
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// run
|
||||
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Issue 27961: some optimizations generate OffPtr with wrong
|
||||
// types, which causes invalid bytecode on Wasm.
|
||||
|
||||
package main
|
||||
|
||||
import "math"
|
||||
|
||||
type Vec2 [2]float64
|
||||
|
||||
func main() {
|
||||
var a Vec2
|
||||
a.A().B().C().D()
|
||||
}
|
||||
|
||||
func (v Vec2) A() Vec2 {
|
||||
return Vec2{v[0], v[0]}
|
||||
}
|
||||
|
||||
func (v Vec2) B() Vec2 {
|
||||
return Vec2{1.0 / v.D(), 0}
|
||||
}
|
||||
|
||||
func (v Vec2) C() Vec2 {
|
||||
return Vec2{v[0], v[0]}
|
||||
}
|
||||
|
||||
func (v Vec2) D() float64 {
|
||||
return math.Sqrt(v[0])
|
||||
}
|
||||
|
|
@ -542,7 +542,7 @@ func fence2(x, y int) {
|
|||
}
|
||||
}
|
||||
|
||||
func fence3(b []int, x, y int64) {
|
||||
func fence3(b, c []int, x, y int64) {
|
||||
if x-1 >= y {
|
||||
if x <= y { // Can't prove because x may have wrapped.
|
||||
return
|
||||
|
|
@ -555,6 +555,8 @@ func fence3(b []int, x, y int64) {
|
|||
}
|
||||
}
|
||||
|
||||
c[len(c)-1] = 0 // Can't prove because len(c) might be 0
|
||||
|
||||
if n := len(b); n > 0 {
|
||||
b[n-1] = 0 // ERROR "Proved IsInBounds$"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue