[dev.boringcrypto.go1.13] all: merge go1.13.12 into dev.boringcrypto.go1.13

Change-Id: I34cc756b36cad8c9583d64db2d23c74c14b894c3
This commit is contained in:
Filippo Valsorda 2020-06-09 13:01:40 -04:00
commit 488ca930b2
7 changed files with 200 additions and 53 deletions

View File

@ -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 {

View File

@ -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")

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -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

View File

@ -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) {

View File

@ -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")
}