mirror of https://github.com/golang/go.git
[dev.boringcrypto.go1.13] all: merge go1.13.12 into dev.boringcrypto.go1.13
Change-Id: I34cc756b36cad8c9583d64db2d23c74c14b894c3
This commit is contained in:
commit
488ca930b2
|
|
@ -976,25 +976,22 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
}
|
||||
|
||||
// Second pass - deallocate any phi inputs which are now dead.
|
||||
// Second pass - deallocate all in-register phi inputs.
|
||||
for i, v := range phis {
|
||||
if !s.values[v.ID].needReg {
|
||||
continue
|
||||
}
|
||||
a := v.Args[idx]
|
||||
if !regValLiveSet.contains(a.ID) {
|
||||
// Input is dead beyond the phi, deallocate
|
||||
// anywhere else it might live.
|
||||
s.freeRegs(s.values[a.ID].regs)
|
||||
} else {
|
||||
// Input is still live.
|
||||
r := phiRegs[i]
|
||||
if r == noRegister {
|
||||
continue
|
||||
}
|
||||
if regValLiveSet.contains(a.ID) {
|
||||
// Input value is still live (it is used by something other than Phi).
|
||||
// Try to move it around before kicking out, if there is a free register.
|
||||
// We generate a Copy in the predecessor block and record it. It will be
|
||||
// deleted if never used.
|
||||
r := phiRegs[i]
|
||||
if r == noRegister {
|
||||
continue
|
||||
}
|
||||
// deleted later if never used.
|
||||
//
|
||||
// Pick a free register. At this point some registers used in the predecessor
|
||||
// block may have been deallocated. Those are the ones used for Phis. Exclude
|
||||
// them (and they are not going to be helpful anyway).
|
||||
|
|
@ -1010,8 +1007,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
s.assignReg(r2, a, c)
|
||||
s.endRegs[p.ID] = append(s.endRegs[p.ID], endReg{r2, a, c})
|
||||
}
|
||||
s.freeReg(r)
|
||||
}
|
||||
s.freeReg(r)
|
||||
}
|
||||
|
||||
// Copy phi ops into new schedule.
|
||||
|
|
@ -1842,6 +1839,11 @@ func (s *regAllocState) shuffle(stacklive [][]ID) {
|
|||
e.process()
|
||||
}
|
||||
}
|
||||
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("post shuffle %s\n", s.f.Name)
|
||||
fmt.Println(s.f.String())
|
||||
}
|
||||
}
|
||||
|
||||
type edgeState struct {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ import (
|
|||
// of Rats are not supported and may lead to errors.
|
||||
type Rat struct {
|
||||
// To make zero values for Rat work w/o initialization,
|
||||
// a zero value of b (len(b) == 0) acts like b == 1.
|
||||
// a zero value of b (len(b) == 0) acts like b == 1. At
|
||||
// the earliest opportunity (when an assignment to the Rat
|
||||
// is made), such uninitialized denominators are set to 1.
|
||||
// a.neg determines the sign of the Rat, b.neg is ignored.
|
||||
a, b Int
|
||||
}
|
||||
|
|
@ -271,7 +273,7 @@ func quotToFloat64(a, b nat) (f float64, exact bool) {
|
|||
func (x *Rat) Float32() (f float32, exact bool) {
|
||||
b := x.b.abs
|
||||
if len(b) == 0 {
|
||||
b = b.set(natOne) // materialize denominator
|
||||
b = natOne
|
||||
}
|
||||
f, exact = quotToFloat32(x.a.abs, b)
|
||||
if x.a.neg {
|
||||
|
|
@ -287,7 +289,7 @@ func (x *Rat) Float32() (f float32, exact bool) {
|
|||
func (x *Rat) Float64() (f float64, exact bool) {
|
||||
b := x.b.abs
|
||||
if len(b) == 0 {
|
||||
b = b.set(natOne) // materialize denominator
|
||||
b = natOne
|
||||
}
|
||||
f, exact = quotToFloat64(x.a.abs, b)
|
||||
if x.a.neg {
|
||||
|
|
@ -297,6 +299,7 @@ func (x *Rat) Float64() (f float64, exact bool) {
|
|||
}
|
||||
|
||||
// SetFrac sets z to a/b and returns z.
|
||||
// If b == 0, SetFrac panics.
|
||||
func (z *Rat) SetFrac(a, b *Int) *Rat {
|
||||
z.a.neg = a.neg != b.neg
|
||||
babs := b.abs
|
||||
|
|
@ -312,11 +315,12 @@ func (z *Rat) SetFrac(a, b *Int) *Rat {
|
|||
}
|
||||
|
||||
// SetFrac64 sets z to a/b and returns z.
|
||||
// If b == 0, SetFrac64 panics.
|
||||
func (z *Rat) SetFrac64(a, b int64) *Rat {
|
||||
z.a.SetInt64(a)
|
||||
if b == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
z.a.SetInt64(a)
|
||||
if b < 0 {
|
||||
b = -b
|
||||
z.a.neg = !z.a.neg
|
||||
|
|
@ -328,21 +332,21 @@ func (z *Rat) SetFrac64(a, b int64) *Rat {
|
|||
// SetInt sets z to x (by making a copy of x) and returns z.
|
||||
func (z *Rat) SetInt(x *Int) *Rat {
|
||||
z.a.Set(x)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
z.b.abs = z.b.abs.setWord(1)
|
||||
return z
|
||||
}
|
||||
|
||||
// SetInt64 sets z to x and returns z.
|
||||
func (z *Rat) SetInt64(x int64) *Rat {
|
||||
z.a.SetInt64(x)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
z.b.abs = z.b.abs.setWord(1)
|
||||
return z
|
||||
}
|
||||
|
||||
// SetUint64 sets z to x and returns z.
|
||||
func (z *Rat) SetUint64(x uint64) *Rat {
|
||||
z.a.SetUint64(x)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
z.b.abs = z.b.abs.setWord(1)
|
||||
return z
|
||||
}
|
||||
|
||||
|
|
@ -352,6 +356,9 @@ func (z *Rat) Set(x *Rat) *Rat {
|
|||
z.a.Set(&x.a)
|
||||
z.b.Set(&x.b)
|
||||
}
|
||||
if len(z.b.abs) == 0 {
|
||||
z.b.abs = z.b.abs.setWord(1)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
|
|
@ -370,20 +377,13 @@ func (z *Rat) Neg(x *Rat) *Rat {
|
|||
}
|
||||
|
||||
// Inv sets z to 1/x and returns z.
|
||||
// If x == 0, Inv panics.
|
||||
func (z *Rat) Inv(x *Rat) *Rat {
|
||||
if len(x.a.abs) == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
z.Set(x)
|
||||
a := z.b.abs
|
||||
if len(a) == 0 {
|
||||
a = a.set(natOne) // materialize numerator
|
||||
}
|
||||
b := z.a.abs
|
||||
if b.cmp(natOne) == 0 {
|
||||
b = b[:0] // normalize denominator
|
||||
}
|
||||
z.a.abs, z.b.abs = a, b // sign doesn't change
|
||||
z.a.abs, z.b.abs = z.b.abs, z.a.abs
|
||||
return z
|
||||
}
|
||||
|
||||
|
|
@ -411,12 +411,19 @@ func (x *Rat) Num() *Int {
|
|||
}
|
||||
|
||||
// Denom returns the denominator of x; it is always > 0.
|
||||
// The result is a reference to x's denominator; it
|
||||
// The result is a reference to x's denominator, unless
|
||||
// x is an uninitialized (zero value) Rat, in which case
|
||||
// the result is a new Int of value 1. (To initialize x,
|
||||
// any operation that sets x will do, including x.Set(x).)
|
||||
// If the result is a reference to x's denominator it
|
||||
// may change if a new value is assigned to x, and vice versa.
|
||||
func (x *Rat) Denom() *Int {
|
||||
x.b.neg = false // the result is always >= 0
|
||||
if len(x.b.abs) == 0 {
|
||||
x.b.abs = x.b.abs.set(natOne) // materialize denominator
|
||||
// Note: If this proves problematic, we could
|
||||
// panic instead and require the Rat to
|
||||
// be explicitly initialized.
|
||||
return &Int{abs: nat{1}}
|
||||
}
|
||||
return &x.b
|
||||
}
|
||||
|
|
@ -424,25 +431,20 @@ func (x *Rat) Denom() *Int {
|
|||
func (z *Rat) norm() *Rat {
|
||||
switch {
|
||||
case len(z.a.abs) == 0:
|
||||
// z == 0 - normalize sign and denominator
|
||||
// z == 0; normalize sign and denominator
|
||||
z.a.neg = false
|
||||
z.b.abs = z.b.abs[:0]
|
||||
fallthrough
|
||||
case len(z.b.abs) == 0:
|
||||
// z is normalized int - nothing to do
|
||||
case z.b.abs.cmp(natOne) == 0:
|
||||
// z is int - normalize denominator
|
||||
z.b.abs = z.b.abs[:0]
|
||||
// z is integer; normalize denominator
|
||||
z.b.abs = z.b.abs.setWord(1)
|
||||
default:
|
||||
// z is fraction; normalize numerator and denominator
|
||||
neg := z.a.neg
|
||||
z.a.neg = false
|
||||
z.b.neg = false
|
||||
if f := NewInt(0).lehmerGCD(nil, nil, &z.a, &z.b); f.Cmp(intOne) != 0 {
|
||||
z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f.abs)
|
||||
z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
|
||||
if z.b.abs.cmp(natOne) == 0 {
|
||||
// z is int - normalize denominator
|
||||
z.b.abs = z.b.abs[:0]
|
||||
}
|
||||
}
|
||||
z.a.neg = neg
|
||||
}
|
||||
|
|
@ -454,6 +456,8 @@ func (z *Rat) norm() *Rat {
|
|||
// returns z.
|
||||
func mulDenom(z, x, y nat) nat {
|
||||
switch {
|
||||
case len(x) == 0 && len(y) == 0:
|
||||
return z.setWord(1)
|
||||
case len(x) == 0:
|
||||
return z.set(y)
|
||||
case len(y) == 0:
|
||||
|
|
@ -509,10 +513,14 @@ func (z *Rat) Sub(x, y *Rat) *Rat {
|
|||
// Mul sets z to the product x*y and returns z.
|
||||
func (z *Rat) Mul(x, y *Rat) *Rat {
|
||||
if x == y {
|
||||
// a squared Rat is positive and can't be reduced
|
||||
// a squared Rat is positive and can't be reduced (no need to call norm())
|
||||
z.a.neg = false
|
||||
z.a.abs = z.a.abs.sqr(x.a.abs)
|
||||
z.b.abs = z.b.abs.sqr(x.b.abs)
|
||||
if len(x.b.abs) == 0 {
|
||||
z.b.abs = z.b.abs.setWord(1)
|
||||
} else {
|
||||
z.b.abs = z.b.abs.sqr(x.b.abs)
|
||||
}
|
||||
return z
|
||||
}
|
||||
z.a.Mul(&x.a, &y.a)
|
||||
|
|
@ -521,7 +529,7 @@ func (z *Rat) Mul(x, y *Rat) *Rat {
|
|||
}
|
||||
|
||||
// Quo sets z to the quotient x/y and returns z.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
// If y == 0, Quo panics.
|
||||
func (z *Rat) Quo(x, y *Rat) *Rat {
|
||||
if len(y.a.abs) == 0 {
|
||||
panic("division by zero")
|
||||
|
|
|
|||
|
|
@ -329,18 +329,40 @@ func TestIssue3521(t *testing.T) {
|
|||
t.Errorf("0) got %s want %s", zero.Denom(), one)
|
||||
}
|
||||
|
||||
// 1a) a zero value remains zero independent of denominator
|
||||
x := new(Rat)
|
||||
x.Denom().Set(new(Int).Neg(b))
|
||||
if x.Cmp(zero) != 0 {
|
||||
t.Errorf("1a) got %s want %s", x, zero)
|
||||
// 1a) the denominator of an (uninitialized) zero value is not shared with the value
|
||||
s := &zero.b
|
||||
d := zero.Denom()
|
||||
if d == s {
|
||||
t.Errorf("1a) got %s (%p) == %s (%p) want different *Int values", d, d, s, s)
|
||||
}
|
||||
|
||||
// 1b) a zero value may have a denominator != 0 and != 1
|
||||
// 1b) the denominator of an (uninitialized) value is a new 1 each time
|
||||
d1 := zero.Denom()
|
||||
d2 := zero.Denom()
|
||||
if d1 == d2 {
|
||||
t.Errorf("1b) got %s (%p) == %s (%p) want different *Int values", d1, d1, d2, d2)
|
||||
}
|
||||
|
||||
// 1c) the denominator of an initialized zero value is shared with the value
|
||||
x := new(Rat)
|
||||
x.Set(x) // initialize x (any operation that sets x explicitly will do)
|
||||
s = &x.b
|
||||
d = x.Denom()
|
||||
if d != s {
|
||||
t.Errorf("1c) got %s (%p) != %s (%p) want identical *Int values", d, d, s, s)
|
||||
}
|
||||
|
||||
// 1d) a zero value remains zero independent of denominator
|
||||
x.Denom().Set(new(Int).Neg(b))
|
||||
if x.Cmp(zero) != 0 {
|
||||
t.Errorf("1d) got %s want %s", x, zero)
|
||||
}
|
||||
|
||||
// 1e) a zero value may have a denominator != 0 and != 1
|
||||
x.Num().Set(a)
|
||||
qab := new(Rat).SetFrac(a, b)
|
||||
if x.Cmp(qab) != 0 {
|
||||
t.Errorf("1b) got %s want %s", x, qab)
|
||||
t.Errorf("1e) got %s want %s", x, qab)
|
||||
}
|
||||
|
||||
// 2a) an integral value becomes a fraction depending on denominator
|
||||
|
|
@ -678,3 +700,29 @@ func BenchmarkRatCmp(b *testing.B) {
|
|||
x.Cmp(y)
|
||||
}
|
||||
}
|
||||
|
||||
// TestIssue34919 verifies that a Rat's denominator is not modified
|
||||
// when simply accessing the Rat value.
|
||||
func TestIssue34919(t *testing.T) {
|
||||
for _, acc := range []struct {
|
||||
name string
|
||||
f func(*Rat)
|
||||
}{
|
||||
{"Float32", func(x *Rat) { x.Float32() }},
|
||||
{"Float64", func(x *Rat) { x.Float64() }},
|
||||
{"Inv", func(x *Rat) { new(Rat).Inv(x) }},
|
||||
{"Sign", func(x *Rat) { x.Sign() }},
|
||||
{"IsInt", func(x *Rat) { x.IsInt() }},
|
||||
{"Num", func(x *Rat) { x.Num() }},
|
||||
// {"Denom", func(x *Rat) { x.Denom() }}, TODO(gri) should we change the API? See issue #33792.
|
||||
} {
|
||||
// A denominator of length 0 is interpreted as 1. Make sure that
|
||||
// "materialization" of the denominator doesn't lead to setting
|
||||
// the underlying array element 0 to 1.
|
||||
r := &Rat{Int{abs: nat{991}}, Int{abs: make(nat, 0, 1)}}
|
||||
acc.f(r)
|
||||
if d := r.b.abs[:1][0]; d != 0 {
|
||||
t.Errorf("%s modified denominator: got %d, want 0", acc.name, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,16 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return runBuiltTestProg(t, exe, name, env...)
|
||||
}
|
||||
|
||||
func runBuiltTestProg(t *testing.T, exe, name string, env ...string) string {
|
||||
if *flagQuick {
|
||||
t.Skip("-quick")
|
||||
}
|
||||
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
cmd := testenv.CleanCmdEnv(exec.Command(exe, name))
|
||||
cmd.Env = append(cmd.Env, env...)
|
||||
if testing.Short() {
|
||||
|
|
@ -64,7 +74,7 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string {
|
|||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatalf("starting %s %s: %v", binary, name, err)
|
||||
t.Fatalf("starting %s %s: %v", exe, name, err)
|
||||
}
|
||||
|
||||
// If the process doesn't complete within 1 minute,
|
||||
|
|
@ -92,7 +102,7 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string {
|
|||
}()
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
t.Logf("%s %s exit status: %v", binary, name, err)
|
||||
t.Logf("%s %s exit status: %v", exe, name, err)
|
||||
}
|
||||
close(done)
|
||||
|
||||
|
|
|
|||
|
|
@ -1862,10 +1862,16 @@ func startTemplateThread() {
|
|||
if GOARCH == "wasm" { // no threads on wasm yet
|
||||
return
|
||||
}
|
||||
|
||||
// Disable preemption to guarantee that the template thread will be
|
||||
// created before a park once haveTemplateThread is set.
|
||||
mp := acquirem()
|
||||
if !atomic.Cas(&newmHandoff.haveTemplateThread, 0, 1) {
|
||||
releasem(mp)
|
||||
return
|
||||
}
|
||||
newm(templateThread, nil)
|
||||
releasem(mp)
|
||||
}
|
||||
|
||||
// templateThread is a thread in a known-good state that exists solely
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package runtime_test
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"math"
|
||||
"net"
|
||||
"runtime"
|
||||
|
|
@ -912,6 +913,29 @@ func TestLockOSThreadAvoidsStatePropagation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLockOSThreadTemplateThreadRace(t *testing.T) {
|
||||
testenv.MustHaveGoRun(t)
|
||||
|
||||
exe, err := buildTestProg(t, "testprog")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
iterations := 100
|
||||
if testing.Short() {
|
||||
// Reduce run time to ~100ms, with much lower probability of
|
||||
// catching issues.
|
||||
iterations = 5
|
||||
}
|
||||
for i := 0; i < iterations; i++ {
|
||||
want := "OK\n"
|
||||
output := runBuiltTestProg(t, exe, "LockOSThreadTemplateThreadRace")
|
||||
if output != want {
|
||||
t.Fatalf("run %d: want %q, got %q", i, want, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fakeSyscall emulates a system call.
|
||||
//go:nosplit
|
||||
func fakeSyscall(duration time.Duration) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package main
|
|||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -30,6 +31,7 @@ func init() {
|
|||
runtime.LockOSThread()
|
||||
})
|
||||
register("LockOSThreadAvoidsStatePropagation", LockOSThreadAvoidsStatePropagation)
|
||||
register("LockOSThreadTemplateThreadRace", LockOSThreadTemplateThreadRace)
|
||||
}
|
||||
|
||||
func LockOSThreadMain() {
|
||||
|
|
@ -195,3 +197,50 @@ func LockOSThreadAvoidsStatePropagation() {
|
|||
runtime.UnlockOSThread()
|
||||
println("OK")
|
||||
}
|
||||
|
||||
func LockOSThreadTemplateThreadRace() {
|
||||
// This test attempts to reproduce the race described in
|
||||
// golang.org/issue/38931. To do so, we must have a stop-the-world
|
||||
// (achieved via ReadMemStats) racing with two LockOSThread calls.
|
||||
//
|
||||
// While this test attempts to line up the timing, it is only expected
|
||||
// to fail (and thus hang) around 2% of the time if the race is
|
||||
// present.
|
||||
|
||||
// Ensure enough Ps to actually run everything in parallel. Though on
|
||||
// <4 core machines, we are still at the whim of the kernel scheduler.
|
||||
runtime.GOMAXPROCS(4)
|
||||
|
||||
go func() {
|
||||
// Stop the world; race with LockOSThread below.
|
||||
var m runtime.MemStats
|
||||
for {
|
||||
runtime.ReadMemStats(&m)
|
||||
}
|
||||
}()
|
||||
|
||||
// Try to synchronize both LockOSThreads.
|
||||
start := time.Now().Add(10*time.Millisecond)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
go func() {
|
||||
for time.Now().Before(start) {
|
||||
}
|
||||
|
||||
// Add work to the local runq to trigger early startm
|
||||
// in handoffp.
|
||||
go func(){}()
|
||||
|
||||
runtime.LockOSThread()
|
||||
runtime.Gosched() // add a preemption point.
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
// If both LockOSThreads completed then we did not hit the race.
|
||||
println("OK")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue