From 6b6e67f9b9ad00ff03b8a46c054b8da4954bfab4 Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Fri, 4 Oct 2019 10:07:36 +0200
Subject: runtime: add support for freebsd/arm64
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Based on work by Mikaël Urankar (@MikaelUrankar),
Shigeru YAMAMOTO (@bsd-hacker) and @myfreeweb.
Updates #24715
Change-Id: If3189a693ca0aa627029e22b0f91534bcf322bc0
Reviewed-on: https://go-review.googlesource.com/c/go/+/198544
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/runtime/defs_freebsd_arm64.go | 257 +++++++++++++++++
src/runtime/os_freebsd_arm64.go | 156 +++++++++++
src/runtime/os_freebsd_noauxv.go | 2 +-
src/runtime/rt0_freebsd_arm64.s | 106 +++++++
src/runtime/signal_arm64.go | 2 +-
src/runtime/signal_freebsd_arm64.go | 66 +++++
src/runtime/stubs_arm64.go | 1 +
src/runtime/sys_freebsd_arm64.s | 537 ++++++++++++++++++++++++++++++++++++
src/runtime/tls_arm64.h | 5 +
src/runtime/vdso_freebsd_arm64.go | 21 ++
10 files changed, 1151 insertions(+), 2 deletions(-)
create mode 100644 src/runtime/defs_freebsd_arm64.go
create mode 100644 src/runtime/os_freebsd_arm64.go
create mode 100644 src/runtime/rt0_freebsd_arm64.s
create mode 100644 src/runtime/signal_freebsd_arm64.go
create mode 100644 src/runtime/sys_freebsd_arm64.s
create mode 100644 src/runtime/vdso_freebsd_arm64.go
(limited to 'src')
diff --git a/src/runtime/defs_freebsd_arm64.go b/src/runtime/defs_freebsd_arm64.go
new file mode 100644
index 0000000000..3eebe5dbb3
--- /dev/null
+++ b/src/runtime/defs_freebsd_arm64.go
@@ -0,0 +1,257 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_freebsd.go
+
+package runtime
+
+import "unsafe"
+
+const (
+ _NBBY = 0x8
+ _CTL_MAXNAME = 0x18
+ _CPU_LEVEL_WHICH = 0x3
+ _CPU_WHICH_PID = 0x2
+)
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _EAGAIN = 0x23
+ _ENOSYS = 0x4e
+
+ _O_NONBLOCK = 0x4
+ _O_CLOEXEC = 0x100000
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_SHARED = 0x1
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_FREE = 0x5
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+
+ _CLOCK_MONOTONIC = 0x4
+ _CLOCK_REALTIME = 0x0
+
+ _UMTX_OP_WAIT_UINT = 0xb
+ _UMTX_OP_WAIT_UINT_PRIVATE = 0xf
+ _UMTX_OP_WAKE = 0x3
+ _UMTX_OP_WAKE_PRIVATE = 0x10
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x2
+ _FPE_INTOVF = 0x1
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0x40
+ _EV_ERROR = 0x4000
+ _EV_EOF = 0x8000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+ _type uint16
+ prio uint16
+}
+
+type thrparam struct {
+ start_func uintptr
+ arg unsafe.Pointer
+ stack_base uintptr
+ stack_size uintptr
+ tls_base unsafe.Pointer
+ tls_size uintptr
+ child_tid unsafe.Pointer // *int64
+ parent_tid *int64
+ flags int32
+ pad_cgo_0 [4]byte
+ rtp *rtprio
+ spare [3]uintptr
+}
+
+type sigset struct {
+ __bits [4]uint32
+}
+
+type stackt struct {
+ ss_sp uintptr
+ ss_size uintptr
+ ss_flags int32
+ pad_cgo_0 [4]byte
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr uint64
+ si_value [8]byte
+ _reason [40]byte
+}
+
+type gpregs struct {
+ gp_x [30]uint64
+ gp_lr uint64
+ gp_sp uint64
+ gp_elr uint64
+ gp_spsr uint32
+ gp_pad int32
+}
+
+type fpregs struct {
+ fp_q [64]uint64 // actually [32]uint128
+ fp_sr uint32
+ fp_cr uint32
+ fp_flags int32
+ fp_pad int32
+}
+
+type mcontext struct {
+ mc_gpregs gpregs
+ mc_fpregs fpregs
+ mc_flags int32
+ mc_pad int32
+ mc_spare [8]uint64
+}
+
+type ucontext struct {
+ uc_sigmask sigset
+ uc_mcontext mcontext
+ uc_link *ucontext
+ uc_stack stackt
+ uc_flags int32
+ __spare__ [4]int32
+ pad_cgo_0 [12]byte
+}
+
+type timespec struct {
+ tv_sec int64
+ tv_nsec int64
+}
+
+//go:nosplit
+func (ts *timespec) setNsec(ns int64) {
+ ts.tv_sec = ns / 1e9
+ ts.tv_nsec = ns % 1e9
+}
+
+type timeval struct {
+ tv_sec int64
+ tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = int64(x)
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type umtx_time struct {
+ _timeout timespec
+ _flags uint32
+ _clockid uint32
+}
+
+type keventt struct {
+ ident uint64
+ filter int16
+ flags uint16
+ fflags uint32
+ data int64
+ udata *byte
+}
+
+type bintime struct {
+ sec int64
+ frac uint64
+}
+
+type vdsoTimehands struct {
+ algo uint32
+ gen uint32
+ scale uint64
+ offset_count uint32
+ counter_mask uint32
+ offset bintime
+ boottime bintime
+ physical uint32
+ res [7]uint32
+}
+
+type vdsoTimekeep struct {
+ ver uint32
+ enabled uint32
+ current uint32
+ pad_cgo_0 [4]byte
+}
+
+const (
+ _VDSO_TK_VER_CURR = 0x1
+
+ vdsoTimehandsSize = 0x58
+ vdsoTimekeepSize = 0x10
+)
diff --git a/src/runtime/os_freebsd_arm64.go b/src/runtime/os_freebsd_arm64.go
new file mode 100644
index 0000000000..800bd2fa6e
--- /dev/null
+++ b/src/runtime/os_freebsd_arm64.go
@@ -0,0 +1,156 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "internal/cpu"
+
+const (
+ hwcap_FP = 1 << 0
+ hwcap_ASIMD = 1 << 1
+ hwcap_EVTSTRM = 1 << 2
+ hwcap_AES = 1 << 3
+ hwcap_PMULL = 1 << 4
+ hwcap_SHA1 = 1 << 5
+ hwcap_SHA2 = 1 << 6
+ hwcap_CRC32 = 1 << 7
+ hwcap_ATOMICS = 1 << 8
+ hwcap_FPHP = 1 << 9
+ hwcap_ASIMDHP = 1 << 10
+ hwcap_CPUID = 1 << 11
+ hwcap_ASIMDRDM = 1 << 12
+ hwcap_JSCVT = 1 << 13
+ hwcap_FCMA = 1 << 14
+ hwcap_LRCPC = 1 << 15
+ hwcap_DCPOP = 1 << 16
+ hwcap_SHA3 = 1 << 17
+ hwcap_SM3 = 1 << 18
+ hwcap_SM4 = 1 << 19
+ hwcap_ASIMDDP = 1 << 20
+ hwcap_SHA512 = 1 << 21
+ hwcap_SVE = 1 << 22
+ hwcap_ASIMDFHM = 1 << 23
+)
+
+func getisar0() uint64
+func getisar1() uint64
+func getpfr0() uint64
+
+// no hwcap support on FreeBSD aarch64, we need to retrieve the info from
+// ID_AA64ISAR0_EL1, ID_AA64ISAR1_EL1 and ID_AA64PFR0_EL1
+func archauxv(tag, val uintptr) {
+ var isar0, isar1, pfr0 uint64
+
+ isar0 = getisar0()
+ isar1 = getisar1()
+ pfr0 = getpfr0()
+
+ // ID_AA64ISAR0_EL1
+ switch extractBits(isar0, 4, 7) {
+ case 1:
+ cpu.HWCap |= hwcap_AES
+ case 2:
+ cpu.HWCap |= hwcap_PMULL | hwcap_AES
+ }
+
+ switch extractBits(isar0, 8, 11) {
+ case 1:
+ cpu.HWCap |= hwcap_SHA1
+ }
+
+ switch extractBits(isar0, 12, 15) {
+ case 1:
+ cpu.HWCap |= hwcap_SHA2
+ case 2:
+ cpu.HWCap |= hwcap_SHA2 | hwcap_SHA512
+ }
+
+ switch extractBits(isar0, 16, 19) {
+ case 1:
+ cpu.HWCap |= hwcap_CRC32
+ }
+
+ switch extractBits(isar0, 20, 23) {
+ case 2:
+ cpu.HWCap |= hwcap_ATOMICS
+ }
+
+ switch extractBits(isar0, 28, 31) {
+ case 1:
+ cpu.HWCap |= hwcap_ASIMDRDM
+ }
+
+ switch extractBits(isar0, 32, 35) {
+ case 1:
+ cpu.HWCap |= hwcap_SHA3
+ }
+
+ switch extractBits(isar0, 36, 39) {
+ case 1:
+ cpu.HWCap |= hwcap_SM3
+ }
+
+ switch extractBits(isar0, 40, 43) {
+ case 1:
+ cpu.HWCap |= hwcap_SM4
+ }
+
+ switch extractBits(isar0, 44, 47) {
+ case 1:
+ cpu.HWCap |= hwcap_ASIMDDP
+ }
+
+ // ID_AA64ISAR1_EL1
+ switch extractBits(isar1, 0, 3) {
+ case 1:
+ cpu.HWCap |= hwcap_DCPOP
+ }
+
+ switch extractBits(isar1, 12, 15) {
+ case 1:
+ cpu.HWCap |= hwcap_JSCVT
+ }
+
+ switch extractBits(isar1, 16, 19) {
+ case 1:
+ cpu.HWCap |= hwcap_FCMA
+ }
+
+ switch extractBits(isar1, 20, 23) {
+ case 1:
+ cpu.HWCap |= hwcap_LRCPC
+ }
+
+ // ID_AA64PFR0_EL1
+ switch extractBits(pfr0, 16, 19) {
+ case 0:
+ cpu.HWCap |= hwcap_FP
+ case 1:
+ cpu.HWCap |= hwcap_FP | hwcap_FPHP
+ }
+
+ switch extractBits(pfr0, 20, 23) {
+ case 0:
+ cpu.HWCap |= hwcap_ASIMD
+ case 1:
+ cpu.HWCap |= hwcap_ASIMD | hwcap_ASIMDHP
+ }
+
+ switch extractBits(pfr0, 32, 35) {
+ case 1:
+ cpu.HWCap |= hwcap_SVE
+ }
+}
+
+func extractBits(data uint64, start, end uint) uint {
+ return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
+}
+
+//go:nosplit
+func cputicks() int64 {
+ // Currently cputicks() is used in blocking profiler and to seed fastrand().
+ // nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+ // TODO: need more entropy to better seed fastrand.
+ return nanotime()
+}
diff --git a/src/runtime/os_freebsd_noauxv.go b/src/runtime/os_freebsd_noauxv.go
index 01efb9b7c9..c6a49927c8 100644
--- a/src/runtime/os_freebsd_noauxv.go
+++ b/src/runtime/os_freebsd_noauxv.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build freebsd
-// +build !arm
+// +build !arm,!arm64
package runtime
diff --git a/src/runtime/rt0_freebsd_arm64.s b/src/runtime/rt0_freebsd_arm64.s
new file mode 100644
index 0000000000..3a348c33e2
--- /dev/null
+++ b/src/runtime/rt0_freebsd_arm64.s
@@ -0,0 +1,106 @@
+// Copyright 2019 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.
+
+#include "textflag.h"
+
+// On FreeBSD argc/argv are passed in R0, not RSP
+TEXT _rt0_arm64_freebsd(SB),NOSPLIT|NOFRAME,$0
+ ADD $8, R0, R1 // argv
+ MOVD 0(R0), R0 // argc
+ BL main(SB)
+
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_arm64_freebsd_lib(SB),NOSPLIT,$184
+ // Preserve callee-save registers.
+ MOVD R19, 24(RSP)
+ MOVD R20, 32(RSP)
+ MOVD R21, 40(RSP)
+ MOVD R22, 48(RSP)
+ MOVD R23, 56(RSP)
+ MOVD R24, 64(RSP)
+ MOVD R25, 72(RSP)
+ MOVD R26, 80(RSP)
+ MOVD R27, 88(RSP)
+ FMOVD F8, 96(RSP)
+ FMOVD F9, 104(RSP)
+ FMOVD F10, 112(RSP)
+ FMOVD F11, 120(RSP)
+ FMOVD F12, 128(RSP)
+ FMOVD F13, 136(RSP)
+ FMOVD F14, 144(RSP)
+ FMOVD F15, 152(RSP)
+ MOVD g, 160(RSP)
+
+ // Initialize g as null in case of using g later e.g. sigaction in cgo_sigaction.go
+ MOVD ZR, g
+
+ MOVD R0, _rt0_arm64_freebsd_lib_argc<>(SB)
+ MOVD R1, _rt0_arm64_freebsd_lib_argv<>(SB)
+
+ // Synchronous initialization.
+ MOVD $runtime·libpreinit(SB), R4
+ BL (R4)
+
+ // Create a new thread to do the runtime initialization and return.
+ MOVD _cgo_sys_thread_create(SB), R4
+ CMP $0, R4
+ BEQ nocgo
+ MOVD $_rt0_arm64_freebsd_lib_go(SB), R0
+ MOVD $0, R1
+ SUB $16, RSP // reserve 16 bytes for sp-8 where fp may be saved.
+ BL (R4)
+ ADD $16, RSP
+ B restore
+
+nocgo:
+ MOVD $0x800000, R0 // stacksize = 8192KB
+ MOVD $_rt0_arm64_freebsd_lib_go(SB), R1
+ MOVD R0, 8(RSP)
+ MOVD R1, 16(RSP)
+ MOVD $runtime·newosproc0(SB),R4
+ BL (R4)
+
+restore:
+ // Restore callee-save registers.
+ MOVD 24(RSP), R19
+ MOVD 32(RSP), R20
+ MOVD 40(RSP), R21
+ MOVD 48(RSP), R22
+ MOVD 56(RSP), R23
+ MOVD 64(RSP), R24
+ MOVD 72(RSP), R25
+ MOVD 80(RSP), R26
+ MOVD 88(RSP), R27
+ FMOVD 96(RSP), F8
+ FMOVD 104(RSP), F9
+ FMOVD 112(RSP), F10
+ FMOVD 120(RSP), F11
+ FMOVD 128(RSP), F12
+ FMOVD 136(RSP), F13
+ FMOVD 144(RSP), F14
+ FMOVD 152(RSP), F15
+ MOVD 160(RSP), g
+ RET
+
+TEXT _rt0_arm64_freebsd_lib_go(SB),NOSPLIT,$0
+ MOVD _rt0_arm64_freebsd_lib_argc<>(SB), R0
+ MOVD _rt0_arm64_freebsd_lib_argv<>(SB), R1
+ MOVD $runtime·rt0_go(SB),R4
+ B (R4)
+
+DATA _rt0_arm64_freebsd_lib_argc<>(SB)/8, $0
+GLOBL _rt0_arm64_freebsd_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_arm64_freebsd_lib_argv<>(SB)/8, $0
+GLOBL _rt0_arm64_freebsd_lib_argv<>(SB),NOPTR, $8
+
+
+TEXT main(SB),NOSPLIT|NOFRAME,$0
+ MOVD $runtime·rt0_go(SB), R2
+ BL (R2)
+exit:
+ MOVD $0, R0
+ MOVD $1, R8 // SYS_exit
+ SVC
+ B exit
diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go
index 7a3b1ccbb8..e1fe62d99d 100644
--- a/src/runtime/signal_arm64.go
+++ b/src/runtime/signal_arm64.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin linux netbsd openbsd
+// +build darwin freebsd linux netbsd openbsd
package runtime
diff --git a/src/runtime/signal_freebsd_arm64.go b/src/runtime/signal_freebsd_arm64.go
new file mode 100644
index 0000000000..159e965a7d
--- /dev/null
+++ b/src/runtime/signal_freebsd_arm64.go
@@ -0,0 +1,66 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+
+func (c *sigctxt) r0() uint64 { return c.regs().mc_gpregs.gp_x[0] }
+func (c *sigctxt) r1() uint64 { return c.regs().mc_gpregs.gp_x[1] }
+func (c *sigctxt) r2() uint64 { return c.regs().mc_gpregs.gp_x[2] }
+func (c *sigctxt) r3() uint64 { return c.regs().mc_gpregs.gp_x[3] }
+func (c *sigctxt) r4() uint64 { return c.regs().mc_gpregs.gp_x[4] }
+func (c *sigctxt) r5() uint64 { return c.regs().mc_gpregs.gp_x[5] }
+func (c *sigctxt) r6() uint64 { return c.regs().mc_gpregs.gp_x[6] }
+func (c *sigctxt) r7() uint64 { return c.regs().mc_gpregs.gp_x[7] }
+func (c *sigctxt) r8() uint64 { return c.regs().mc_gpregs.gp_x[8] }
+func (c *sigctxt) r9() uint64 { return c.regs().mc_gpregs.gp_x[9] }
+func (c *sigctxt) r10() uint64 { return c.regs().mc_gpregs.gp_x[10] }
+func (c *sigctxt) r11() uint64 { return c.regs().mc_gpregs.gp_x[11] }
+func (c *sigctxt) r12() uint64 { return c.regs().mc_gpregs.gp_x[12] }
+func (c *sigctxt) r13() uint64 { return c.regs().mc_gpregs.gp_x[13] }
+func (c *sigctxt) r14() uint64 { return c.regs().mc_gpregs.gp_x[14] }
+func (c *sigctxt) r15() uint64 { return c.regs().mc_gpregs.gp_x[15] }
+func (c *sigctxt) r16() uint64 { return c.regs().mc_gpregs.gp_x[16] }
+func (c *sigctxt) r17() uint64 { return c.regs().mc_gpregs.gp_x[17] }
+func (c *sigctxt) r18() uint64 { return c.regs().mc_gpregs.gp_x[18] }
+func (c *sigctxt) r19() uint64 { return c.regs().mc_gpregs.gp_x[19] }
+func (c *sigctxt) r20() uint64 { return c.regs().mc_gpregs.gp_x[20] }
+func (c *sigctxt) r21() uint64 { return c.regs().mc_gpregs.gp_x[21] }
+func (c *sigctxt) r22() uint64 { return c.regs().mc_gpregs.gp_x[22] }
+func (c *sigctxt) r23() uint64 { return c.regs().mc_gpregs.gp_x[23] }
+func (c *sigctxt) r24() uint64 { return c.regs().mc_gpregs.gp_x[24] }
+func (c *sigctxt) r25() uint64 { return c.regs().mc_gpregs.gp_x[25] }
+func (c *sigctxt) r26() uint64 { return c.regs().mc_gpregs.gp_x[26] }
+func (c *sigctxt) r27() uint64 { return c.regs().mc_gpregs.gp_x[27] }
+func (c *sigctxt) r28() uint64 { return c.regs().mc_gpregs.gp_x[28] }
+func (c *sigctxt) r29() uint64 { return c.regs().mc_gpregs.gp_x[29] }
+func (c *sigctxt) lr() uint64 { return c.regs().mc_gpregs.gp_lr }
+func (c *sigctxt) sp() uint64 { return c.regs().mc_gpregs.gp_sp }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint64 { return c.regs().mc_gpregs.gp_elr }
+
+func (c *sigctxt) fault() uint64 { return c.info.si_addr }
+
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
+
+func (c *sigctxt) set_pc(x uint64) { c.regs().mc_gpregs.gp_elr = x }
+func (c *sigctxt) set_sp(x uint64) { c.regs().mc_gpregs.gp_sp = x }
+func (c *sigctxt) set_lr(x uint64) { c.regs().mc_gpregs.gp_lr = x }
+func (c *sigctxt) set_r28(x uint64) { c.regs().mc_gpregs.gp_x[28] = x }
+
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) { c.info.si_addr = x }
diff --git a/src/runtime/stubs_arm64.go b/src/runtime/stubs_arm64.go
index 44c566e602..8a1c49cc0f 100644
--- a/src/runtime/stubs_arm64.go
+++ b/src/runtime/stubs_arm64.go
@@ -7,3 +7,4 @@ package runtime
// Called from assembly only; declared for go vet.
func load_g()
func save_g()
+func emptyfunc()
diff --git a/src/runtime/sys_freebsd_arm64.s b/src/runtime/sys_freebsd_arm64.s
new file mode 100644
index 0000000000..808daa063a
--- /dev/null
+++ b/src/runtime/sys_freebsd_arm64.s
@@ -0,0 +1,537 @@
+// Copyright 2019 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.
+
+//
+// System calls and other sys.stuff for arm64, FreeBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+#define CLOCK_REALTIME 0
+#define CLOCK_MONOTONIC 4
+#define FD_CLOEXEC 1
+#define F_SETFD 2
+#define F_GETFL 3
+#define F_SETFL 4
+#define O_NONBLOCK 4
+
+#define SYS_exit 1
+#define SYS_read 3
+#define SYS_write 4
+#define SYS_open 5
+#define SYS_close 6
+#define SYS_getpid 20
+#define SYS_kill 37
+#define SYS_sigaltstack 53
+#define SYS_munmap 73
+#define SYS_madvise 75
+#define SYS_setitimer 83
+#define SYS_fcntl 92
+#define SYS___sysctl 202
+#define SYS_nanosleep 240
+#define SYS_clock_gettime 232
+#define SYS_sched_yield 331
+#define SYS_sigprocmask 340
+#define SYS_kqueue 362
+#define SYS_kevent 363
+#define SYS_sigaction 416
+#define SYS_thr_exit 431
+#define SYS_thr_self 432
+#define SYS_thr_kill 433
+#define SYS__umtx_op 454
+#define SYS_thr_new 455
+#define SYS_mmap 477
+#define SYS_cpuset_getaffinity 487
+#define SYS_pipe2 542
+
+TEXT runtime·emptyfunc(SB),0,$0-0
+ RET
+
+// func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
+TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
+ MOVD addr+0(FP), R0
+ MOVW mode+8(FP), R1
+ MOVW val+12(FP), R2
+ MOVD uaddr1+16(FP), R3
+ MOVD ut+24(FP), R4
+ MOVD $SYS__umtx_op, R8
+ SVC
+ MOVW R0, ret+32(FP)
+ RET
+
+// func thr_new(param *thrparam, size int32) int32
+TEXT runtime·thr_new(SB),NOSPLIT,$0
+ MOVD param+0(FP), R0
+ MOVW size+8(FP), R1
+ MOVD $SYS_thr_new, R8
+ SVC
+ MOVW R0, ret+16(FP)
+ RET
+
+// func thr_start()
+TEXT runtime·thr_start(SB),NOSPLIT,$0
+ // set up g
+ MOVD m_g0(R0), g
+ MOVD R0, g_m(g)
+ BL runtime·emptyfunc(SB) // fault if stack check is wrong
+ BL runtime·mstart(SB)
+
+ MOVD $2, R8 // crash (not reached)
+ MOVD R8, (R8)
+ RET
+
+// func exit(code int32)
+TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
+ MOVW code+0(FP), R0
+ MOVD $SYS_exit, R8
+ SVC
+ MOVD $0, R0
+ MOVD R0, (R0)
+
+// func exitThread(wait *uint32)
+TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
+ MOVD wait+0(FP), R0
+ // We're done using the stack.
+ MOVW $0, R1
+ STLRW R1, (R0)
+ MOVW $0, R0
+ MOVD $SYS_thr_exit, R8
+ SVC
+ JMP 0(PC)
+
+// func open(name *byte, mode, perm int32) int32
+TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0-20
+ MOVD name+0(FP), R0
+ MOVW mode+8(FP), R1
+ MOVW perm+12(FP), R2
+ MOVD $SYS_open, R8
+ SVC
+ BCC ok
+ MOVW $-1, R0
+ok:
+ MOVW R0, ret+16(FP)
+ RET
+
+// func closefd(fd int32) int32
+TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0-12
+ MOVW fd+0(FP), R0
+ MOVD $SYS_close, R8
+ SVC
+ BCC ok
+ MOVW $-1, R0
+ok:
+ MOVW R0, ret+8(FP)
+ RET
+
+// func pipe() (r, w int32, errno int32)
+TEXT runtime·pipe(SB),NOSPLIT|NOFRAME,$0-12
+ ADD $8, RSP, R0
+ MOVW $0, R1
+ MOVD $SYS_pipe2, R8
+ SVC
+ BCC ok
+ NEG R0, R0
+ok:
+ MOVW R0, errno+8(FP)
+ RET
+
+// func pipe2(flags int32) (r, w int32, errno int32)
+TEXT runtime·pipe2(SB),NOSPLIT|NOFRAME,$0-20
+ ADD $16, RSP, R0
+ MOVW flags+0(FP), R1
+ MOVD $SYS_pipe2, R8
+ SVC
+ BCC ok
+ NEG R0, R0
+ok:
+ MOVW R0, errno+16(FP)
+ RET
+
+// func write1(fd uintptr, p unsafe.Pointer, n int32) int32
+TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0-28
+ MOVD fd+0(FP), R0
+ MOVD p+8(FP), R1
+ MOVW n+16(FP), R2
+ MOVD $SYS_write, R8
+ SVC
+ BCC ok
+ NEG R0, R0 // caller expects negative errno
+ok:
+ MOVW R0, ret+24(FP)
+ RET
+
+// func read(fd int32, p unsafe.Pointer, n int32) int32
+TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0-28
+ MOVW fd+0(FP), R0
+ MOVD p+8(FP), R1
+ MOVW n+16(FP), R2
+ MOVD $SYS_read, R8
+ SVC
+ BCC ok
+ NEG R0, R0 // caller expects negative errno
+ok:
+ MOVW R0, ret+24(FP)
+ RET
+
+// func usleep(usec uint32)
+TEXT runtime·usleep(SB),NOSPLIT,$24-4
+ MOVWU usec+0(FP), R3
+ MOVD R3, R5
+ MOVW $1000000, R4
+ UDIV R4, R3
+ MOVD R3, 8(RSP)
+ MUL R3, R4
+ SUB R4, R5
+ MOVW $1000, R4
+ MUL R4, R5
+ MOVD R5, 16(RSP)
+
+ // nanosleep(&ts, 0)
+ ADD $8, RSP, R0
+ MOVD $0, R1
+ MOVD $SYS_nanosleep, R8
+ SVC
+ RET
+
+// func raise(sig uint32)
+TEXT runtime·raise(SB),NOSPLIT,$8
+ MOVD $8(RSP), R0 // arg 1 &8(RSP)
+ MOVD $SYS_thr_self, R8
+ SVC
+ MOVD 8(RSP), R0 // arg 1 pid
+ MOVW sig+0(FP), R1
+ MOVD $SYS_thr_kill, R8
+ SVC
+ RET
+
+// func raiseproc(sig uint32)
+TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
+ MOVD $SYS_getpid, R8
+ SVC
+ MOVW sig+0(FP), R1
+ MOVD $SYS_kill, R8
+ SVC
+ RET
+
+// func setitimer(mode int32, new, old *itimerval)
+TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
+ MOVW mode+0(FP), R0
+ MOVD new+8(FP), R1
+ MOVD old+16(FP), R2
+ MOVD $SYS_setitimer, R8
+ SVC
+ RET
+
+// func fallback_walltime() (sec int64, nsec int32)
+TEXT runtime·fallback_walltime(SB),NOSPLIT,$24-12
+ MOVW $CLOCK_REALTIME, R0
+ MOVD $8(RSP), R1
+ MOVD $SYS_clock_gettime, R8
+ SVC
+ MOVD 8(RSP), R0 // sec
+ MOVW 16(RSP), R1 // nsec
+ MOVD R0, sec+0(FP)
+ MOVW R1, nsec+8(FP)
+ RET
+
+// func fallback_nanotime() int64
+TEXT runtime·fallback_nanotime(SB),NOSPLIT,$24-8
+ MOVD $CLOCK_MONOTONIC, R0
+ MOVD $8(RSP), R1
+ MOVD $SYS_clock_gettime, R8
+ SVC
+ MOVD 8(RSP), R0 // sec
+ MOVW 16(RSP), R2 // nsec
+
+ // sec is in R0, nsec in R2
+ // return nsec in R2
+ MOVD $1000000000, R3
+ MUL R3, R0
+ ADD R2, R0
+
+ MOVD R0, ret+0(FP)
+ RET
+
+// func asmSigaction(sig uintptr, new, old *sigactiont) int32
+TEXT runtime·asmSigaction(SB),NOSPLIT|NOFRAME,$0
+ MOVD sig+0(FP), R0 // arg 1 sig
+ MOVD new+8(FP), R1 // arg 2 act
+ MOVD old+16(FP), R2 // arg 3 oact
+ MOVD $SYS_sigaction, R8
+ SVC
+ BCC ok
+ MOVW $-1, R0
+ok:
+ MOVW R0, ret+24(FP)
+ RET
+
+// func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVW sig+8(FP), R0
+ MOVD info+16(FP), R1
+ MOVD ctx+24(FP), R2
+ MOVD fn+0(FP), R11
+ BL (R11)
+ RET
+
+// func sigtramp()
+TEXT runtime·sigtramp(SB),NOSPLIT,$192
+ // Save callee-save registers in the case of signal forwarding.
+ // Please refer to https://golang.org/issue/31827 .
+ MOVD R19, 8*4(RSP)
+ MOVD R20, 8*5(RSP)
+ MOVD R21, 8*6(RSP)
+ MOVD R22, 8*7(RSP)
+ MOVD R23, 8*8(RSP)
+ MOVD R24, 8*9(RSP)
+ MOVD R25, 8*10(RSP)
+ MOVD R26, 8*11(RSP)
+ MOVD R27, 8*12(RSP)
+ MOVD g, 8*13(RSP)
+ MOVD R29, 8*14(RSP)
+ FMOVD F8, 8*15(RSP)
+ FMOVD F9, 8*16(RSP)
+ FMOVD F10, 8*17(RSP)
+ FMOVD F11, 8*18(RSP)
+ FMOVD F12, 8*19(RSP)
+ FMOVD F13, 8*20(RSP)
+ FMOVD F14, 8*21(RSP)
+ FMOVD F15, 8*22(RSP)
+
+ // this might be called in external code context,
+ // where g is not set.
+ // first save R0, because runtime·load_g will clobber it
+ MOVW R0, 8(RSP)
+ MOVBU runtime·iscgo(SB), R0
+ CMP $0, R0
+ BEQ 2(PC)
+ BL runtime·load_g(SB)
+
+ MOVD R1, 16(RSP)
+ MOVD R2, 24(RSP)
+ MOVD $runtime·sigtrampgo(SB), R0
+ BL (R0)
+
+ // Restore callee-save registers.
+ MOVD 8*4(RSP), R19
+ MOVD 8*5(RSP), R20
+ MOVD 8*6(RSP), R21
+ MOVD 8*7(RSP), R22
+ MOVD 8*8(RSP), R23
+ MOVD 8*9(RSP), R24
+ MOVD 8*10(RSP), R25
+ MOVD 8*11(RSP), R26
+ MOVD 8*12(RSP), R27
+ MOVD 8*13(RSP), g
+ MOVD 8*14(RSP), R29
+ FMOVD 8*15(RSP), F8
+ FMOVD 8*16(RSP), F9
+ FMOVD 8*17(RSP), F10
+ FMOVD 8*18(RSP), F11
+ FMOVD 8*19(RSP), F12
+ FMOVD 8*20(RSP), F13
+ FMOVD 8*21(RSP), F14
+ FMOVD 8*22(RSP), F15
+
+ RET
+
+// func mmap(addr uintptr, n uintptr, prot int, flags int, fd int, off int64) (ret uintptr, err error)
+TEXT runtime·mmap(SB),NOSPLIT|NOFRAME,$0
+ MOVD addr+0(FP), R0
+ MOVD n+8(FP), R1
+ MOVW prot+16(FP), R2
+ MOVW flags+20(FP), R3
+ MOVW fd+24(FP), R4
+ MOVW off+28(FP), R5
+ MOVD $SYS_mmap, R8
+ SVC
+ BCS fail
+ MOVD R0, p+32(FP)
+ MOVD $0, err+40(FP)
+ RET
+fail:
+ MOVD $0, p+32(FP)
+ MOVD R0, err+40(FP)
+ RET
+
+// func munmap(addr uintptr, n uintptr) (err error)
+TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
+ MOVD addr+0(FP), R0
+ MOVD n+8(FP), R1
+ MOVD $SYS_munmap, R8
+ SVC
+ BCS fail
+ RET
+fail:
+ MOVD $0, R0
+ MOVD R0, (R0) // crash
+
+// func madvise(addr unsafe.Pointer, n uintptr, flags int32) int32
+TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
+ MOVD addr+0(FP), R0
+ MOVD n+8(FP), R1
+ MOVW flags+16(FP), R2
+ MOVD $SYS_madvise, R8
+ SVC
+ BCC ok
+ MOVW $-1, R0
+ok:
+ MOVW R0, ret+24(FP)
+ RET
+
+// func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+TEXT runtime·sysctl(SB),NOSPLIT,$0
+ MOVD mib+0(FP), R0
+ MOVD miblen+8(FP), R1
+ MOVD out+16(FP), R2
+ MOVD size+24(FP), R3
+ MOVD dst+32(FP), R4
+ MOVD ndst+40(FP), R5
+ MOVD $SYS___sysctl, R8
+ SVC
+ BCC ok
+ NEG R0, R0
+ok:
+ MOVW R0, ret+48(FP)
+ RET
+
+// func sigaltstack(new, old *stackt)
+TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0
+ MOVD new+0(FP), R0
+ MOVD old+8(FP), R1
+ MOVD $SYS_sigaltstack, R8
+ SVC
+ BCS fail
+ RET
+fail:
+ MOVD $0, R0
+ MOVD R0, (R0) // crash
+
+// func osyield()
+TEXT runtime·osyield(SB),NOSPLIT|NOFRAME,$0
+ MOVD $SYS_sched_yield, R8
+ SVC
+ RET
+
+// func sigprocmask(how int32, new, old *sigset)
+TEXT runtime·sigprocmask(SB),NOSPLIT|NOFRAME,$0-24
+ MOVW how+0(FP), R0
+ MOVD new+8(FP), R1
+ MOVD old+16(FP), R2
+ MOVD $SYS_sigprocmask, R8
+ SVC
+ BCS fail
+ RET
+fail:
+ MOVD $0, R0
+ MOVD R0, (R0) // crash
+
+// func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32
+TEXT runtime·cpuset_getaffinity(SB),NOSPLIT|NOFRAME,$0-44
+ MOVD level+0(FP), R0
+ MOVD which+8(FP), R1
+ MOVD id+16(FP), R2
+ MOVD size+24(FP), R3
+ MOVD mask+32(FP), R4
+ MOVD $SYS_cpuset_getaffinity, R8
+ SVC
+ BCC ok
+ MOVW $-1, R0
+ok:
+ MOVW R0, ret+40(FP)
+ RET
+
+// func kqueue() int32
+TEXT runtime·kqueue(SB),NOSPLIT|NOFRAME,$0
+ MOVD $SYS_kqueue, R8
+ SVC
+ BCC ok
+ MOVW $-1, R0
+ok:
+ MOVW R0, ret+0(FP)
+ RET
+
+// func kevent(kq int, ch unsafe.Pointer, nch int, ev unsafe.Pointer, nev int, ts *Timespec) (n int, err error)
+TEXT runtime·kevent(SB),NOSPLIT,$0
+ MOVW kq+0(FP), R0
+ MOVD ch+8(FP), R1
+ MOVW nch+16(FP), R2
+ MOVD ev+24(FP), R3
+ MOVW nev+32(FP), R4
+ MOVD ts+40(FP), R5
+ MOVD $SYS_kevent, R8
+ SVC
+ BCC ok
+ NEG R0, R0
+ok:
+ MOVW R0, ret+48(FP)
+ RET
+
+// func closeonexec(fd int32)
+TEXT runtime·closeonexec(SB),NOSPLIT|NOFRAME,$0
+ MOVW fd+0(FP), R0
+ MOVD $F_SETFD, R1
+ MOVD $FD_CLOEXEC, R2
+ MOVD $SYS_fcntl, R8
+ SVC
+ RET
+
+// func runtime·setNonblock(fd int32)
+TEXT runtime·setNonblock(SB),NOSPLIT,$0-4
+ MOVW fd+0(FP), R0
+ MOVD $F_GETFL, R1
+ MOVD $0, R2
+ MOVD $SYS_fcntl, R8
+ SVC
+ ORR $O_NONBLOCK, R0, R2
+ MOVW fd+0(FP), R0
+ MOVW $F_SETFL, R1
+ MOVW $SYS_fcntl, R7
+ SVC
+ RET
+
+// func getCntxct(physical bool) uint32
+TEXT runtime·getCntxct(SB),NOSPLIT,$0
+ MOVB physical+0(FP), R0
+ CMP $0, R0
+ BEQ 3(PC)
+
+ // get CNTPCT (Physical Count Register) into x0
+ // mrs x0, cntpct_el0 = d53be020
+ WORD $0xd53be020 // SIGILL
+ B 2(PC)
+
+ // get CNTVCT (Virtual Count Register) into x0
+ // mrs x0, cntvct_el0 = d53be040
+ WORD $0xd53be040
+
+ MOVW R0, ret+8(FP)
+ RET
+
+// func getisar0() uint64
+TEXT runtime·getisar0(SB),NOSPLIT,$0
+ // get Instruction Set Attributes 0 into x0
+ // mrs x0, ID_AA64ISAR0_EL1 = d5380600
+ WORD $0xd5380600
+ MOVD R0, ret+0(FP)
+ RET
+
+// func getisar1() uint64
+TEXT runtime·getisar1(SB),NOSPLIT,$0
+ // get Instruction Set Attributes 1 into x0
+ // mrs x0, ID_AA64ISAR1_EL1 = d5380620
+ WORD $0xd5380620
+ MOVD R0, ret+0(FP)
+ RET
+
+// func getpfr0() uint64
+TEXT runtime·getpfr0(SB),NOSPLIT,$0
+ // get Processor Feature Register 0 into x0
+ // mrs x0, ID_AA64PFR0_EL1 = d5380400
+ WORD $0xd5380400
+ MOVD R0, ret+0(FP)
+ RET
diff --git a/src/runtime/tls_arm64.h b/src/runtime/tls_arm64.h
index 27f517c155..f60f4f6d5b 100644
--- a/src/runtime/tls_arm64.h
+++ b/src/runtime/tls_arm64.h
@@ -20,6 +20,11 @@
#define MRS_TPIDR_R0 WORD $0xd53bd060 // MRS TPIDRRO_EL0, R0
#endif
+#ifdef GOOS_freebsd
+#define TPIDR TPIDR_EL0
+#define MRS_TPIDR_R0 WORD $0xd53bd040 // MRS TPIDR_EL0, R0
+#endif
+
#ifdef GOOS_netbsd
#define TPIDR TPIDRRO_EL0
#define MRS_TPIDR_R0 WORD $0xd53bd040 // MRS TPIDRRO_EL0, R0
diff --git a/src/runtime/vdso_freebsd_arm64.go b/src/runtime/vdso_freebsd_arm64.go
new file mode 100644
index 0000000000..7d9f62d5f9
--- /dev/null
+++ b/src/runtime/vdso_freebsd_arm64.go
@@ -0,0 +1,21 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+const (
+ _VDSO_TH_ALGO_ARM_GENTIM = 1
+)
+
+func getCntxct(physical bool) uint32
+
+//go:nosplit
+func (th *vdsoTimehands) getTimecounter() (uint32, bool) {
+ switch th.algo {
+ case _VDSO_TH_ALGO_ARM_GENTIM:
+ return getCntxct(false), true
+ default:
+ return 0, false
+ }
+}
--
cgit v1.3-5-g9baa
From 3d457f1a3669f8609018bfdc981de7da2f0e95d9 Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Fri, 4 Oct 2019 11:53:22 +0200
Subject: cmd/dist: add support for freebsd/arm64
Updates #24715
Change-Id: I110a10a5d5ed4a471f67f35cbcdcbea296c5dcaf
Reviewed-on: https://go-review.googlesource.com/c/go/+/198542
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/cmd/dist/build.go | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 6c8e558f29..bc629e1d9e 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -1485,6 +1485,7 @@ var cgoEnabled = map[string]bool{
"freebsd/386": true,
"freebsd/amd64": true,
"freebsd/arm": true,
+ "freebsd/arm64": false,
"illumos/amd64": true,
"linux/386": true,
"linux/amd64": true,
--
cgit v1.3-5-g9baa
From 096126de6b33a0c7831aebcdde00081876991438 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills"
Date: Fri, 25 Oct 2019 13:55:10 -0400
Subject: os/signal: derive TestAtomicStop timeout from overall test timeout
Previously, TestAtomicStop used a hard-coded 2-second timeout.
That empirically is not long enough on certain builders. Rather than
adjusting it to a different arbitrary value, use a slice of the
overall timeout for the test binary. If everything is working, we
won't block nearly that long anyway.
Updates #35085
Change-Id: I7b789388e3152413395088088fc497419976cf5c
Reviewed-on: https://go-review.googlesource.com/c/go/+/203499
Run-TryBot: Bryan C. Mills
Reviewed-by: Brad Fitzpatrick
---
src/os/signal/signal_test.go | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index 7aa3d7805b..ee884bc632 100644
--- a/src/os/signal/signal_test.go
+++ b/src/os/signal/signal_test.go
@@ -22,6 +22,22 @@ import (
"time"
)
+var testDeadline time.Time
+
+func TestMain(m *testing.M) {
+ flag.Parse()
+
+ // TODO(golang.org/issue/28135): Remove this setup and use t.Deadline instead.
+ timeoutFlag := flag.Lookup("test.timeout")
+ if timeoutFlag != nil {
+ if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 {
+ testDeadline = time.Now().Add(d)
+ }
+ }
+
+ os.Exit(m.Run())
+}
+
func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
// Sleep multiple times to give the kernel more tries to
// deliver the signal.
@@ -392,7 +408,11 @@ func TestAtomicStop(t *testing.T) {
const execs = 10
for i := 0; i < execs; i++ {
- cmd := exec.Command(os.Args[0], "-test.run=TestAtomicStop")
+ timeout := "0"
+ if !testDeadline.IsZero() {
+ timeout = testDeadline.Sub(time.Now()).String()
+ }
+ cmd := exec.Command(os.Args[0], "-test.run=TestAtomicStop", "-test.timeout="+timeout)
cmd.Env = append(os.Environ(), "GO_TEST_ATOMIC_STOP=1")
out, err := cmd.CombinedOutput()
if err == nil {
@@ -431,6 +451,14 @@ func TestAtomicStop(t *testing.T) {
// either catch a signal or die from it.
func atomicStopTestProgram() {
const tries = 10
+
+ timeout := 2 * time.Second
+ if !testDeadline.IsZero() {
+ // Give each try an equal slice of the deadline, with one slice to spare for
+ // cleanup.
+ timeout = testDeadline.Sub(time.Now()) / (tries + 1)
+ }
+
pid := syscall.Getpid()
printed := false
for i := 0; i < tries; i++ {
@@ -453,7 +481,7 @@ func atomicStopTestProgram() {
select {
case <-cs:
- case <-time.After(2 * time.Second):
+ case <-time.After(timeout):
if !printed {
fmt.Print("lost signal on tries:")
printed = true
--
cgit v1.3-5-g9baa
From 8bb47a5eecf57b88c1b9cc088a21ae869c6a6764 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills"
Date: Fri, 25 Oct 2019 14:07:10 -0400
Subject: net/http: skip failing test on windows-amd64-longtest builder
bradfitz is actively thinking about a proper fix.
In the meantime, skip the test to suss out any other failures in the builder.
Updates #35122
Change-Id: I9bf0640222e3d385c1a3e2be5ab52b80d3e8c21a
Reviewed-on: https://go-review.googlesource.com/c/go/+/203500
Run-TryBot: Bryan C. Mills
Reviewed-by: Brad Fitzpatrick
---
src/net/http/transport_test.go | 4 ++++
1 file changed, 4 insertions(+)
(limited to 'src')
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index f76530b8fa..3673ed29f0 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -22,6 +22,7 @@ import (
"fmt"
"go/token"
"internal/nettrace"
+ "internal/testenv"
"io"
"io/ioutil"
"log"
@@ -2354,6 +2355,9 @@ func TestCancelRequestWithChannel(t *testing.T) {
}
func TestCancelRequestWithChannelBeforeDo_Cancel(t *testing.T) {
+ if os.Getenv("GO_BUILDER_NAME") == "windows-amd64-longtest" {
+ testenv.SkipFlaky(t, 35122)
+ }
testCancelRequestWithChannelBeforeDo(t, false)
}
func TestCancelRequestWithChannelBeforeDo_Context(t *testing.T) {
--
cgit v1.3-5-g9baa
From 316fb95f4fd94fb00f7746c32ae85a82d5be1b81 Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Fri, 25 Oct 2019 20:48:07 +0200
Subject: runtime: define emptyfunc as static function in assembly for
freebsd/arm64
CL 198544 broke the linux/arm64 build because it declares emptyfunc for
GOARCH=arm64, but only freebsd/arm64 defines it. Make it a static
assembly function specific for freebsd/arm64 and remove the stub.
Fixes #35160
Change-Id: I5fd94249b60c6fd259c251407b6eccc8fa512934
Reviewed-on: https://go-review.googlesource.com/c/go/+/203418
Reviewed-by: Bryan C. Mills
---
src/runtime/stubs_arm64.go | 1 -
src/runtime/sys_freebsd_arm64.s | 4 ++--
2 files changed, 2 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/runtime/stubs_arm64.go b/src/runtime/stubs_arm64.go
index 8a1c49cc0f..44c566e602 100644
--- a/src/runtime/stubs_arm64.go
+++ b/src/runtime/stubs_arm64.go
@@ -7,4 +7,3 @@ package runtime
// Called from assembly only; declared for go vet.
func load_g()
func save_g()
-func emptyfunc()
diff --git a/src/runtime/sys_freebsd_arm64.s b/src/runtime/sys_freebsd_arm64.s
index 808daa063a..ca2ea4f1d6 100644
--- a/src/runtime/sys_freebsd_arm64.s
+++ b/src/runtime/sys_freebsd_arm64.s
@@ -48,7 +48,7 @@
#define SYS_cpuset_getaffinity 487
#define SYS_pipe2 542
-TEXT runtime·emptyfunc(SB),0,$0-0
+TEXT emptyfunc<>(SB),0,$0-0
RET
// func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
@@ -77,7 +77,7 @@ TEXT runtime·thr_start(SB),NOSPLIT,$0
// set up g
MOVD m_g0(R0), g
MOVD R0, g_m(g)
- BL runtime·emptyfunc(SB) // fault if stack check is wrong
+ BL emptyfunc<>(SB) // fault if stack check is wrong
BL runtime·mstart(SB)
MOVD $2, R8 // crash (not reached)
--
cgit v1.3-5-g9baa
From dcad830621abe2856e4540e4b9afbb7873f939ee Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills"
Date: Thu, 24 Oct 2019 15:11:18 -0400
Subject: cmd/go: implement svn support in module mode
mod_get_svn passes, and I also tested this manually on a real-world svn-hosted package:
example.com$ go mod init example.com
go: creating new go.mod: module example.com
example.com$ GOPROXY=direct GONOSUMDB=llvm.org go get -d llvm.org/llvm/bindings/go/llvm
go: finding llvm.org/llvm latest
go: finding llvm.org/llvm/bindings/go/llvm latest
go: downloading llvm.org/llvm v0.0.0-20191022153947-000000375505
go: extracting llvm.org/llvm v0.0.0-20191022153947-000000375505
example.com$ go list llvm.org/llvm/bindings/...
llvm.org/llvm/bindings/go
llvm.org/llvm/bindings/go/llvm
Fixes #26092
Change-Id: Iefe2151b82a0225c73bb6f8dd7cd8a352897d4c0
Reviewed-on: https://go-review.googlesource.com/c/go/+/203497
Run-TryBot: Bryan C. Mills
Reviewed-by: Jay Conrod
---
doc/go1.14.html | 4 +
src/cmd/go/internal/modfetch/codehost/svn.go | 154 +++++++++++++++++++++++++++
src/cmd/go/internal/modfetch/codehost/vcs.go | 92 ++++++++--------
src/cmd/go/testdata/script/mod_get_svn.txt | 18 ++--
4 files changed, 215 insertions(+), 53 deletions(-)
create mode 100644 src/cmd/go/internal/modfetch/codehost/svn.go
(limited to 'src')
diff --git a/doc/go1.14.html b/doc/go1.14.html
index 4a69ec4ed4..0160d9a781 100644
--- a/doc/go1.14.html
+++ b/doc/go1.14.html
@@ -133,6 +133,10 @@ TODO
trimming the ".mod" extension and appending ".sum".
+
+ The go command now supports Subversion repositories in module mode.
+
+
Runtime
diff --git a/src/cmd/go/internal/modfetch/codehost/svn.go b/src/cmd/go/internal/modfetch/codehost/svn.go
new file mode 100644
index 0000000000..6ec9e59c9c
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/codehost/svn.go
@@ -0,0 +1,154 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package codehost
+
+import (
+ "archive/zip"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "os"
+ "path"
+ "path/filepath"
+ "time"
+)
+
+func svnParseStat(rev, out string) (*RevInfo, error) {
+ var log struct {
+ Logentry struct {
+ Revision int64 `xml:"revision,attr"`
+ Date string `xml:"date"`
+ } `xml:"logentry"`
+ }
+ if err := xml.Unmarshal([]byte(out), &log); err != nil {
+ return nil, vcsErrorf("unexpected response from svn log --xml: %v\n%s", err, out)
+ }
+
+ t, err := time.Parse(time.RFC3339, log.Logentry.Date)
+ if err != nil {
+ return nil, vcsErrorf("unexpected response from svn log --xml: %v\n%s", err, out)
+ }
+
+ info := &RevInfo{
+ Name: fmt.Sprintf("%d", log.Logentry.Revision),
+ Short: fmt.Sprintf("%012d", log.Logentry.Revision),
+ Time: t.UTC(),
+ Version: rev,
+ }
+ return info, nil
+}
+
+func svnReadZip(dst io.Writer, workDir, rev, subdir, remote string) (err error) {
+ // The subversion CLI doesn't provide a command to write the repository
+ // directly to an archive, so we need to export it to the local filesystem
+ // instead. Unfortunately, the local filesystem might apply arbitrary
+ // normalization to the filenames, so we need to obtain those directly.
+ //
+ // 'svn export' prints the filenames as they are written, but from reading the
+ // svn source code (as of revision 1868933), those filenames are encoded using
+ // the system locale rather than preserved byte-for-byte from the origin. For
+ // our purposes, that won't do, but we don't want to go mucking around with
+ // the user's locale settings either — that could impact error messages, and
+ // we don't know what locales the user has available or what LC_* variables
+ // their platform supports.
+ //
+ // Instead, we'll do a two-pass export: first we'll run 'svn list' to get the
+ // canonical filenames, then we'll 'svn export' and look for those filenames
+ // in the local filesystem. (If there is an encoding problem at that point, we
+ // would probably reject the resulting module anyway.)
+
+ remotePath := remote
+ if subdir != "" {
+ remotePath += "/" + subdir
+ }
+
+ out, err := Run(workDir, []string{
+ "svn", "list",
+ "--non-interactive",
+ "--xml",
+ "--incremental",
+ "--recursive",
+ "--revision", rev,
+ "--", remotePath,
+ })
+ if err != nil {
+ return err
+ }
+
+ type listEntry struct {
+ Kind string `xml:"kind,attr"`
+ Name string `xml:"name"`
+ Size int64 `xml:"size"`
+ }
+ var list struct {
+ Entries []listEntry `xml:"entry"`
+ }
+ if err := xml.Unmarshal(out, &list); err != nil {
+ return vcsErrorf("unexpected response from svn list --xml: %v\n%s", err, out)
+ }
+
+ exportDir := filepath.Join(workDir, "export")
+ // Remove any existing contents from a previous (failed) run.
+ if err := os.RemoveAll(exportDir); err != nil {
+ return err
+ }
+ defer os.RemoveAll(exportDir) // best-effort
+
+ _, err = Run(workDir, []string{
+ "svn", "export",
+ "--non-interactive",
+ "--quiet",
+
+ // Suppress any platform- or host-dependent transformations.
+ "--native-eol", "LF",
+ "--ignore-externals",
+ "--ignore-keywords",
+
+ "--revision", rev,
+ "--", remotePath,
+ exportDir,
+ })
+ if err != nil {
+ return err
+ }
+
+ // Scrape the exported files out of the filesystem and encode them in the zipfile.
+
+ // “All files in the zip file are expected to be
+ // nested in a single top-level directory, whose name is not specified.”
+ // We'll (arbitrarily) choose the base of the remote path.
+ basePath := path.Join(path.Base(remote), subdir)
+
+ zw := zip.NewWriter(dst)
+ for _, e := range list.Entries {
+ if e.Kind != "file" {
+ continue
+ }
+
+ zf, err := zw.Create(path.Join(basePath, e.Name))
+ if err != nil {
+ return err
+ }
+
+ f, err := os.Open(filepath.Join(exportDir, e.Name))
+ if err != nil {
+ if os.IsNotExist(err) {
+ return vcsErrorf("file reported by 'svn list', but not written by 'svn export': %s", e.Name)
+ }
+ return fmt.Errorf("error opening file created by 'svn export': %v", err)
+ }
+
+ n, err := io.Copy(zf, f)
+ f.Close()
+ if err != nil {
+ return err
+ }
+ if n != e.Size {
+ return vcsErrorf("file size differs between 'svn list' and 'svn export': file %s listed as %v bytes, but exported as %v bytes", e.Name, e.Size, n)
+ }
+ }
+
+ return zw.Close()
+}
diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go
index c9f77bf3b2..7284557f4b 100644
--- a/src/cmd/go/internal/modfetch/codehost/vcs.go
+++ b/src/cmd/go/internal/modfetch/codehost/vcs.go
@@ -5,7 +5,7 @@
package codehost
import (
- "encoding/xml"
+ "errors"
"fmt"
"internal/lazyregexp"
"io"
@@ -122,19 +122,20 @@ func newVCSRepo(vcs, remote string) (Repo, error) {
const vcsWorkDirType = "vcs1."
type vcsCmd struct {
- vcs string // vcs name "hg"
- init func(remote string) []string // cmd to init repo to track remote
- tags func(remote string) []string // cmd to list local tags
- tagRE *lazyregexp.Regexp // regexp to extract tag names from output of tags cmd
- branches func(remote string) []string // cmd to list local branches
- branchRE *lazyregexp.Regexp // regexp to extract branch names from output of tags cmd
- badLocalRevRE *lazyregexp.Regexp // regexp of names that must not be served out of local cache without doing fetch first
- statLocal func(rev, remote string) []string // cmd to stat local rev
- parseStat func(rev, out string) (*RevInfo, error) // cmd to parse output of statLocal
- fetch []string // cmd to fetch everything from remote
- latest string // name of latest commit on remote (tip, HEAD, etc)
- readFile func(rev, file, remote string) []string // cmd to read rev's file
- readZip func(rev, subdir, remote, target string) []string // cmd to read rev's subdir as zip file
+ vcs string // vcs name "hg"
+ init func(remote string) []string // cmd to init repo to track remote
+ tags func(remote string) []string // cmd to list local tags
+ tagRE *lazyregexp.Regexp // regexp to extract tag names from output of tags cmd
+ branches func(remote string) []string // cmd to list local branches
+ branchRE *lazyregexp.Regexp // regexp to extract branch names from output of tags cmd
+ badLocalRevRE *lazyregexp.Regexp // regexp of names that must not be served out of local cache without doing fetch first
+ statLocal func(rev, remote string) []string // cmd to stat local rev
+ parseStat func(rev, out string) (*RevInfo, error) // cmd to parse output of statLocal
+ fetch []string // cmd to fetch everything from remote
+ latest string // name of latest commit on remote (tip, HEAD, etc)
+ readFile func(rev, file, remote string) []string // cmd to read rev's file
+ readZip func(rev, subdir, remote, target string) []string // cmd to read rev's subdir as zip file
+ doReadZip func(dst io.Writer, workDir, rev, subdir, remote string) error // arbitrary function to read rev's subdir as zip file
}
var re = lazyregexp.New
@@ -191,7 +192,7 @@ var vcsCmds = map[string]*vcsCmd{
readFile: func(rev, file, remote string) []string {
return []string{"svn", "cat", "--", remote + "/" + file + "@" + rev}
},
- // TODO: zip
+ doReadZip: svnReadZip,
},
"bzr": {
@@ -418,7 +419,7 @@ func (r *vcsRepo) DescendsFrom(rev, tag string) (bool, error) {
}
func (r *vcsRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, err error) {
- if r.cmd.readZip == nil {
+ if r.cmd.readZip == nil && r.cmd.doReadZip == nil {
return nil, vcsErrorf("ReadZip not implemented for %s", r.cmd.vcs)
}
@@ -435,7 +436,17 @@ func (r *vcsRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
if err != nil {
return nil, err
}
- if r.cmd.vcs == "fossil" {
+ if r.cmd.doReadZip != nil {
+ lw := &limitedWriter{
+ W: f,
+ N: maxSize,
+ ErrLimitReached: errors.New("ReadZip: encoded file exceeds allowed size"),
+ }
+ err = r.cmd.doReadZip(lw, r.dir, rev, subdir, r.remote)
+ if err == nil {
+ _, err = f.Seek(0, io.SeekStart)
+ }
+ } else if r.cmd.vcs == "fossil" {
// If you run
// fossil zip -R .fossil --name prefix trunk /tmp/x.zip
// fossil fails with "unable to create directory /tmp" [sic].
@@ -502,31 +513,6 @@ func hgParseStat(rev, out string) (*RevInfo, error) {
return info, nil
}
-func svnParseStat(rev, out string) (*RevInfo, error) {
- var log struct {
- Logentry struct {
- Revision int64 `xml:"revision,attr"`
- Date string `xml:"date"`
- } `xml:"logentry"`
- }
- if err := xml.Unmarshal([]byte(out), &log); err != nil {
- return nil, vcsErrorf("unexpected response from svn log --xml: %v\n%s", err, out)
- }
-
- t, err := time.Parse(time.RFC3339, log.Logentry.Date)
- if err != nil {
- return nil, vcsErrorf("unexpected response from svn log --xml: %v\n%s", err, out)
- }
-
- info := &RevInfo{
- Name: fmt.Sprintf("%d", log.Logentry.Revision),
- Short: fmt.Sprintf("%012d", log.Logentry.Revision),
- Time: t.UTC(),
- Version: rev,
- }
- return info, nil
-}
-
func bzrParseStat(rev, out string) (*RevInfo, error) {
var revno int64
var tm time.Time
@@ -606,3 +592,25 @@ func fossilParseStat(rev, out string) (*RevInfo, error) {
}
return nil, vcsErrorf("unexpected response from fossil info: %q", out)
}
+
+type limitedWriter struct {
+ W io.Writer
+ N int64
+ ErrLimitReached error
+}
+
+func (l *limitedWriter) Write(p []byte) (n int, err error) {
+ if l.N > 0 {
+ max := len(p)
+ if l.N < int64(max) {
+ max = int(l.N)
+ }
+ n, err = l.W.Write(p[:max])
+ l.N -= int64(n)
+ if err != nil || n >= len(p) {
+ return n, err
+ }
+ }
+
+ return n, l.ErrLimitReached
+}
diff --git a/src/cmd/go/testdata/script/mod_get_svn.txt b/src/cmd/go/testdata/script/mod_get_svn.txt
index 1a5376dec0..3817fce9b6 100644
--- a/src/cmd/go/testdata/script/mod_get_svn.txt
+++ b/src/cmd/go/testdata/script/mod_get_svn.txt
@@ -18,13 +18,10 @@ env GO111MODULE=on
env GOPROXY=direct
env GOSUMDB=off
-# Attempting to get a module zip using svn should fail with a reasonable
-# message instead of a panic.
-# TODO(golang.org/issue/26092): Really, it shouldn't fail at all.
-! go get -d vcs-test.golang.org/svn/hello.svn
-stderr 'ReadZip not implemented for svn'
-! go install .
-stderr 'ReadZip not implemented for svn'
+# Attempting to get a module zip using svn should succeed.
+go get vcs-test.golang.org/svn/hello.svn@000000000001
+exists $GOPATH/pkg/mod/cache/download/vcs-test.golang.org/svn/hello.svn/@v/v0.0.0-20170922011245-000000000001.zip
+exists $GOPATH/bin/hello.svn$GOEXE
# Attempting to get a nonexistent module using svn should fail with a
# reasonable message instead of a panic.
@@ -34,7 +31,6 @@ stderr 'go get vcs-test.golang.org/svn/nonexistent.svn: no matching versions for
-- go.mod --
module golang/go/issues/28943/main
--- main.go --
-package main
-import _ "vcs-test.golang.org/svn/hello.svn"
-func main() {}
+-- go.sum --
+vcs-test.golang.org/svn/hello.svn v0.0.0-20170922011245-000000000001 h1:rZjvboXMfQICKXdhx/QHqJ2Y/AQsJVrXnwGqwcTxQiw=
+vcs-test.golang.org/svn/hello.svn v0.0.0-20170922011245-000000000001/go.mod h1:0memnh/BRLuxiK2zF4rvUgz6ts/fhhB28l3ULFWPusc=
--
cgit v1.3-5-g9baa
From 46e0d724b3f14fd0d350123bbf101e815b493791 Mon Sep 17 00:00:00 2001
From: pokutuna
Date: Fri, 25 Oct 2019 18:58:48 +0000
Subject: net/http: fix comment TimeoutHandler no longer supports Flusher
Fixes #35161
Updates #34439
Change-Id: I978534cbb8b9fb32c115dba0066cf099c61d8ee9
GitHub-Last-Rev: d60581635e8cefb7cfc4b571057542395034c575
GitHub-Pull-Request: golang/go#35162
Reviewed-on: https://go-review.googlesource.com/c/go/+/203478
Reviewed-by: Bryan C. Mills
Run-TryBot: Bryan C. Mills
TryBot-Result: Gobot Gobot
---
src/net/http/server.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/net/http/server.go b/src/net/http/server.go
index ff93e59bc0..b2c071fc21 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -3182,8 +3182,8 @@ func (srv *Server) onceSetNextProtoDefaults() {
// After such a timeout, writes by h to its ResponseWriter will return
// ErrHandlerTimeout.
//
-// TimeoutHandler supports the Flusher and Pusher interfaces but does not
-// support the Hijacker interface.
+// TimeoutHandler supports the Pusher interface but does not support
+// the Hijacker or Flusher interfaces.
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
return &timeoutHandler{
handler: h,
--
cgit v1.3-5-g9baa
From 3f834114ab617eb7b414cb12e7ca8085b5fe3a5c Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Fri, 27 Sep 2019 12:27:51 -0400
Subject: runtime: add general suspendG/resumeG
Currently, the process of suspending a goroutine is tied to stack
scanning. In preparation for non-cooperative preemption, this CL
abstracts this into general purpose suspendG/resumeG functions.
suspendG and resumeG closely follow the existing scang and restartg
functions with one exception: the addition of a _Gpreempted status.
Currently, preemption tasks (stack scanning) are carried out by the
target goroutine if it's in _Grunning. In this new approach, the task
is always carried out by the goroutine that called suspendG. Thus, we
need a reliable way to drive the target goroutine out of _Grunning
until the requesting goroutine is ready to resume it. The new
_Gpreempted state provides the handshake: when a runnable goroutine
responds to a preemption request, it now parks itself and enters
_Gpreempted. The requesting goroutine races to put it in _Gwaiting,
which gives it ownership, but also the responsibility to start it
again.
This CL adds several TODOs about improving the synchronization on the
G status. The existing code already has these problems; we're just
taking note of them.
The next CL will remove the now-dead scang and preemptscan.
For #10958, #24543.
Change-Id: I16dbf87bea9d50399cc86719c156f48e67198f16
Reviewed-on: https://go-review.googlesource.com/c/go/+/201137
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/runtime/mgcmark.go | 16 +++-
src/runtime/preempt.go | 225 +++++++++++++++++++++++++++++++++++++++++++++++
src/runtime/proc.go | 56 +++++++++++-
src/runtime/runtime2.go | 21 +++--
src/runtime/stack.go | 5 ++
src/runtime/traceback.go | 1 +
6 files changed, 313 insertions(+), 11 deletions(-)
create mode 100644 src/runtime/preempt.go
(limited to 'src')
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index 645083db07..adfdaced18 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -211,14 +211,24 @@ func markroot(gcw *gcWork, i uint32) {
userG.waitreason = waitReasonGarbageCollectionScan
}
- // TODO: scang blocks until gp's stack has
- // been scanned, which may take a while for
+ // TODO: suspendG blocks (and spins) until gp
+ // stops, which may take a while for
// running goroutines. Consider doing this in
// two phases where the first is non-blocking:
// we scan the stacks we can and ask running
// goroutines to scan themselves; and the
// second blocks.
- scang(gp, gcw)
+ stopped := suspendG(gp)
+ if stopped.dead {
+ gp.gcscandone = true
+ return
+ }
+ if gp.gcscandone {
+ throw("g already scanned")
+ }
+ scanstack(gp, gcw)
+ gp.gcscandone = true
+ resumeG(stopped)
if selfScan {
casgstatus(userG, _Gwaiting, _Grunning)
diff --git a/src/runtime/preempt.go b/src/runtime/preempt.go
new file mode 100644
index 0000000000..0565fd6360
--- /dev/null
+++ b/src/runtime/preempt.go
@@ -0,0 +1,225 @@
+// Copyright 2019 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.
+
+// Goroutine preemption
+//
+// A goroutine can be preempted at any safe-point. Currently, there
+// are a few categories of safe-points:
+//
+// 1. A blocked safe-point occurs for the duration that a goroutine is
+// descheduled, blocked on synchronization, or in a system call.
+//
+// 2. Synchronous safe-points occur when a running goroutine checks
+// for a preemption request.
+//
+// At both blocked and synchronous safe-points, a goroutine's CPU
+// state is minimal and the garbage collector has complete information
+// about its entire stack. This makes it possible to deschedule a
+// goroutine with minimal space, and to precisely scan a goroutine's
+// stack.
+//
+// Synchronous safe-points are implemented by overloading the stack
+// bound check in function prologues. To preempt a goroutine at the
+// next synchronous safe-point, the runtime poisons the goroutine's
+// stack bound to a value that will cause the next stack bound check
+// to fail and enter the stack growth implementation, which will
+// detect that it was actually a preemption and redirect to preemption
+// handling.
+
+package runtime
+
+type suspendGState struct {
+ g *g
+
+ // dead indicates the goroutine was not suspended because it
+ // is dead. This goroutine could be reused after the dead
+ // state was observed, so the caller must not assume that it
+ // remains dead.
+ dead bool
+
+ // stopped indicates that this suspendG transitioned the G to
+ // _Gwaiting via g.preemptStop and thus is responsible for
+ // readying it when done.
+ stopped bool
+}
+
+// suspendG suspends goroutine gp at a safe-point and returns the
+// state of the suspended goroutine. The caller gets read access to
+// the goroutine until it calls resumeG.
+//
+// It is safe for multiple callers to attempt to suspend the same
+// goroutine at the same time. The goroutine may execute between
+// subsequent successful suspend operations. The current
+// implementation grants exclusive access to the goroutine, and hence
+// multiple callers will serialize. However, the intent is to grant
+// shared read access, so please don't depend on exclusive access.
+//
+// This must be called from the system stack and the user goroutine on
+// the current M (if any) must be in a preemptible state. This
+// prevents deadlocks where two goroutines attempt to suspend each
+// other and both are in non-preemptible states. There are other ways
+// to resolve this deadlock, but this seems simplest.
+//
+// TODO(austin): What if we instead required this to be called from a
+// user goroutine? Then we could deschedule the goroutine while
+// waiting instead of blocking the thread. If two goroutines tried to
+// suspend each other, one of them would win and the other wouldn't
+// complete the suspend until it was resumed. We would have to be
+// careful that they couldn't actually queue up suspend for each other
+// and then both be suspended. This would also avoid the need for a
+// kernel context switch in the synchronous case because we could just
+// directly schedule the waiter. The context switch is unavoidable in
+// the signal case.
+//
+//go:systemstack
+func suspendG(gp *g) suspendGState {
+ if mp := getg().m; mp.curg != nil && readgstatus(mp.curg) == _Grunning {
+ // Since we're on the system stack of this M, the user
+ // G is stuck at an unsafe point. If another goroutine
+ // were to try to preempt m.curg, it could deadlock.
+ throw("suspendG from non-preemptible goroutine")
+ }
+
+ // See https://golang.org/cl/21503 for justification of the yield delay.
+ const yieldDelay = 10 * 1000
+ var nextYield int64
+
+ // Drive the goroutine to a preemption point.
+ stopped := false
+ for i := 0; ; i++ {
+ switch s := readgstatus(gp); s {
+ default:
+ if s&_Gscan != 0 {
+ // Someone else is suspending it. Wait
+ // for them to finish.
+ //
+ // TODO: It would be nicer if we could
+ // coalesce suspends.
+ break
+ }
+
+ dumpgstatus(gp)
+ throw("invalid g status")
+
+ case _Gdead:
+ // Nothing to suspend.
+ //
+ // preemptStop may need to be cleared, but
+ // doing that here could race with goroutine
+ // reuse. Instead, goexit0 clears it.
+ return suspendGState{dead: true}
+
+ case _Gcopystack:
+ // The stack is being copied. We need to wait
+ // until this is done.
+
+ case _Gpreempted:
+ // We (or someone else) suspended the G. Claim
+ // ownership of it by transitioning it to
+ // _Gwaiting.
+ if !casGFromPreempted(gp, _Gpreempted, _Gwaiting) {
+ break
+ }
+
+ // We stopped the G, so we have to ready it later.
+ stopped = true
+
+ s = _Gwaiting
+ fallthrough
+
+ case _Grunnable, _Gsyscall, _Gwaiting:
+ // Claim goroutine by setting scan bit.
+ // This may race with execution or readying of gp.
+ // The scan bit keeps it from transition state.
+ if !castogscanstatus(gp, s, s|_Gscan) {
+ break
+ }
+
+ // Clear the preemption request. It's safe to
+ // reset the stack guard because we hold the
+ // _Gscan bit and thus own the stack.
+ gp.preemptStop = false
+ gp.preempt = false
+ gp.stackguard0 = gp.stack.lo + _StackGuard
+
+ // The goroutine was already at a safe-point
+ // and we've now locked that in.
+ //
+ // TODO: It would be much better if we didn't
+ // leave it in _Gscan, but instead gently
+ // prevented its scheduling until resumption.
+ // Maybe we only use this to bump a suspended
+ // count and the scheduler skips suspended
+ // goroutines? That wouldn't be enough for
+ // {_Gsyscall,_Gwaiting} -> _Grunning. Maybe
+ // for all those transitions we need to check
+ // suspended and deschedule?
+ return suspendGState{g: gp, stopped: stopped}
+
+ case _Grunning:
+ // Optimization: if there is already a pending preemption request
+ // (from the previous loop iteration), don't bother with the atomics.
+ if gp.preemptStop && gp.preempt && gp.stackguard0 == stackPreempt {
+ break
+ }
+
+ // Temporarily block state transitions.
+ if !castogscanstatus(gp, _Grunning, _Gscanrunning) {
+ break
+ }
+
+ // Request synchronous preemption.
+ gp.preemptStop = true
+ gp.preempt = true
+ gp.stackguard0 = stackPreempt
+
+ // TODO: Inject asynchronous preemption.
+
+ casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
+ }
+
+ // TODO: Don't busy wait. This loop should really only
+ // be a simple read/decide/CAS loop that only fails if
+ // there's an active race. Once the CAS succeeds, we
+ // should queue up the preemption (which will require
+ // it to be reliable in the _Grunning case, not
+ // best-effort) and then sleep until we're notified
+ // that the goroutine is suspended.
+ if i == 0 {
+ nextYield = nanotime() + yieldDelay
+ }
+ if nanotime() < nextYield {
+ procyield(10)
+ } else {
+ osyield()
+ nextYield = nanotime() + yieldDelay/2
+ }
+ }
+}
+
+// resumeG undoes the effects of suspendG, allowing the suspended
+// goroutine to continue from its current safe-point.
+func resumeG(state suspendGState) {
+ if state.dead {
+ // We didn't actually stop anything.
+ return
+ }
+
+ gp := state.g
+ switch s := readgstatus(gp); s {
+ default:
+ dumpgstatus(gp)
+ throw("unexpected g status")
+
+ case _Grunnable | _Gscan,
+ _Gwaiting | _Gscan,
+ _Gsyscall | _Gscan:
+ casfrom_Gscanstatus(gp, s, s&^_Gscan)
+ }
+
+ if state.stopped {
+ // We stopped it, so we need to re-schedule it.
+ ready(gp, 0, true)
+ }
+}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 524d75e3c7..3964941b9c 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -738,7 +738,8 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
case _Gscanrunnable,
_Gscanwaiting,
_Gscanrunning,
- _Gscansyscall:
+ _Gscansyscall,
+ _Gscanpreempted:
if newval == oldval&^_Gscan {
success = atomic.Cas(&gp.atomicstatus, oldval, newval)
}
@@ -844,6 +845,28 @@ func casgcopystack(gp *g) uint32 {
}
}
+// casGToPreemptScan transitions gp from _Grunning to _Gscan|_Gpreempted.
+//
+// TODO(austin): This is the only status operation that both changes
+// the status and locks the _Gscan bit. Rethink this.
+func casGToPreemptScan(gp *g, old, new uint32) {
+ if old != _Grunning || new != _Gscan|_Gpreempted {
+ throw("bad g transition")
+ }
+ for !atomic.Cas(&gp.atomicstatus, _Grunning, _Gscan|_Gpreempted) {
+ }
+}
+
+// casGFromPreempted attempts to transition gp from _Gpreempted to
+// _Gwaiting. If successful, the caller is responsible for
+// re-scheduling gp.
+func casGFromPreempted(gp *g, old, new uint32) bool {
+ if old != _Gpreempted || new != _Gwaiting {
+ throw("bad g transition")
+ }
+ return atomic.Cas(&gp.atomicstatus, _Gpreempted, _Gwaiting)
+}
+
// scang blocks until gp's stack has been scanned.
// It might be scanned by scang or it might be scanned by the goroutine itself.
// Either way, the stack scan has completed when scang returns.
@@ -1676,7 +1699,6 @@ func oneNewExtraM() {
gp.syscallsp = gp.sched.sp
gp.stktopsp = gp.sched.sp
gp.gcscanvalid = true
- gp.gcscandone = true
// malg returns status as _Gidle. Change to _Gdead before
// adding to allg where GC can see it. We use _Gdead to hide
// this from tracebacks and stack scans since it isn't a
@@ -2838,6 +2860,32 @@ func gopreempt_m(gp *g) {
goschedImpl(gp)
}
+// preemptPark parks gp and puts it in _Gpreempted.
+//
+//go:systemstack
+func preemptPark(gp *g) {
+ if trace.enabled {
+ traceGoPark(traceEvGoBlock, 0)
+ }
+ status := readgstatus(gp)
+ if status&^_Gscan != _Grunning {
+ dumpgstatus(gp)
+ throw("bad g status")
+ }
+ gp.waitreason = waitReasonPreempted
+ // Transition from _Grunning to _Gscan|_Gpreempted. We can't
+ // be in _Grunning when we dropg because then we'd be running
+ // without an M, but the moment we're in _Gpreempted,
+ // something could claim this G before we've fully cleaned it
+ // up. Hence, we set the scan bit to lock down further
+ // transitions until we can dropg.
+ casGToPreemptScan(gp, _Grunning, _Gscan|_Gpreempted)
+ dropg()
+ casfrom_Gscanstatus(gp, _Gscan|_Gpreempted, _Gpreempted)
+
+ schedule()
+}
+
// Finishes execution of the current goroutine.
func goexit1() {
if raceenabled {
@@ -2861,6 +2909,7 @@ func goexit0(gp *g) {
locked := gp.lockedm != 0
gp.lockedm = 0
_g_.m.lockedg = 0
+ gp.preemptStop = false
gp.paniconfault = false
gp._defer = nil // should be true already but just in case.
gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data.
@@ -4436,7 +4485,8 @@ func checkdead() {
}
s := readgstatus(gp)
switch s &^ _Gscan {
- case _Gwaiting:
+ case _Gwaiting,
+ _Gpreempted:
grunning++
case _Grunnable,
_Grunning,
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index c5023027be..7eac58eb2c 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -78,6 +78,13 @@ const (
// stack is owned by the goroutine that put it in _Gcopystack.
_Gcopystack // 8
+ // _Gpreempted means this goroutine stopped itself for a
+ // suspendG preemption. It is like _Gwaiting, but nothing is
+ // yet responsible for ready()ing it. Some suspendG must CAS
+ // the status to _Gwaiting to take responsibility for
+ // ready()ing this G.
+ _Gpreempted // 9
+
// _Gscan combined with one of the above states other than
// _Grunning indicates that GC is scanning the stack. The
// goroutine is not executing user code and the stack is owned
@@ -89,11 +96,12 @@ const (
//
// atomicstatus&~Gscan gives the state the goroutine will
// return to when the scan completes.
- _Gscan = 0x1000
- _Gscanrunnable = _Gscan + _Grunnable // 0x1001
- _Gscanrunning = _Gscan + _Grunning // 0x1002
- _Gscansyscall = _Gscan + _Gsyscall // 0x1003
- _Gscanwaiting = _Gscan + _Gwaiting // 0x1004
+ _Gscan = 0x1000
+ _Gscanrunnable = _Gscan + _Grunnable // 0x1001
+ _Gscanrunning = _Gscan + _Grunning // 0x1002
+ _Gscansyscall = _Gscan + _Gsyscall // 0x1003
+ _Gscanwaiting = _Gscan + _Gwaiting // 0x1004
+ _Gscanpreempted = _Gscan + _Gpreempted // 0x1009
)
const (
@@ -411,6 +419,7 @@ type g struct {
waitsince int64 // approx time when the g become blocked
waitreason waitReason // if status==Gwaiting
preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
+ preemptStop bool // transition to _Gpreempted on preemption; otherwise, just deschedule
paniconfault bool // panic (instead of crash) on unexpected fault address
preemptscan bool // preempted g does scan for gc
gcscandone bool // g has scanned stack; protected by _Gscan bit in status
@@ -906,6 +915,7 @@ const (
waitReasonTraceReaderBlocked // "trace reader (blocked)"
waitReasonWaitForGCCycle // "wait for GC cycle"
waitReasonGCWorkerIdle // "GC worker (idle)"
+ waitReasonPreempted // "preempted"
)
var waitReasonStrings = [...]string{
@@ -934,6 +944,7 @@ var waitReasonStrings = [...]string{
waitReasonTraceReaderBlocked: "trace reader (blocked)",
waitReasonWaitForGCCycle: "wait for GC cycle",
waitReasonGCWorkerIdle: "GC worker (idle)",
+ waitReasonPreempted: "preempted",
}
func (w waitReason) String() string {
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 93f9769899..3b92c89ff0 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -1017,6 +1017,11 @@ func newstack() {
if thisg.m.p == 0 && thisg.m.locks == 0 {
throw("runtime: g is running but p is not")
}
+
+ if gp.preemptStop {
+ preemptPark(gp) // never returns
+ }
+
// Synchronize with scang.
casgstatus(gp, _Grunning, _Gwaiting)
if gp.preemptscan {
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 0e4b75a7e6..9be7d739d1 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -860,6 +860,7 @@ var gStatusStrings = [...]string{
_Gwaiting: "waiting",
_Gdead: "dead",
_Gcopystack: "copystack",
+ _Gpreempted: "preempted",
}
func goroutineheader(gp *g) {
--
cgit v1.3-5-g9baa
From 1b79afe460c329c1db75456c3278600a4b451b41 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Fri, 27 Sep 2019 12:31:33 -0400
Subject: runtime: remove old stack scanning code
This removes scang and preemptscan, since the stack scanning code now
uses suspendG.
For #10958, #24543.
Change-Id: Ic868bf5d6dcce40662a82cb27bb996cb74d0720e
Reviewed-on: https://go-review.googlesource.com/c/go/+/201138
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/runtime/proc.go | 113 ------------------------------------------------
src/runtime/runtime2.go | 1 -
src/runtime/stack.go | 29 +------------
3 files changed, 1 insertion(+), 142 deletions(-)
(limited to 'src')
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 3964941b9c..9e40bc8c94 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -802,14 +802,6 @@ func casgstatus(gp *g, oldval, newval uint32) {
if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
throw("casgstatus: waiting for Gwaiting but is Grunnable")
}
- // Help GC if needed.
- // if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
- // gp.preemptscan = false
- // systemstack(func() {
- // gcphasework(gp)
- // })
- // }
- // But meanwhile just yield.
if i == 0 {
nextYield = nanotime() + yieldDelay
}
@@ -867,111 +859,6 @@ func casGFromPreempted(gp *g, old, new uint32) bool {
return atomic.Cas(&gp.atomicstatus, _Gpreempted, _Gwaiting)
}
-// scang blocks until gp's stack has been scanned.
-// It might be scanned by scang or it might be scanned by the goroutine itself.
-// Either way, the stack scan has completed when scang returns.
-func scang(gp *g, gcw *gcWork) {
- // Invariant; we (the caller, markroot for a specific goroutine) own gp.gcscandone.
- // Nothing is racing with us now, but gcscandone might be set to true left over
- // from an earlier round of stack scanning (we scan twice per GC).
- // We use gcscandone to record whether the scan has been done during this round.
-
- gp.gcscandone = false
-
- // See https://golang.org/cl/21503 for justification of the yield delay.
- const yieldDelay = 10 * 1000
- var nextYield int64
-
- // Endeavor to get gcscandone set to true,
- // either by doing the stack scan ourselves or by coercing gp to scan itself.
- // gp.gcscandone can transition from false to true when we're not looking
- // (if we asked for preemption), so any time we lock the status using
- // castogscanstatus we have to double-check that the scan is still not done.
-loop:
- for i := 0; !gp.gcscandone; i++ {
- switch s := readgstatus(gp); s {
- default:
- dumpgstatus(gp)
- throw("stopg: invalid status")
-
- case _Gdead:
- // No stack.
- gp.gcscandone = true
- break loop
-
- case _Gcopystack:
- // Stack being switched. Go around again.
-
- case _Grunnable, _Gsyscall, _Gwaiting:
- // Claim goroutine by setting scan bit.
- // Racing with execution or readying of gp.
- // The scan bit keeps them from running
- // the goroutine until we're done.
- if castogscanstatus(gp, s, s|_Gscan) {
- if !gp.gcscandone {
- scanstack(gp, gcw)
- gp.gcscandone = true
- }
- restartg(gp)
- break loop
- }
-
- case _Gscanwaiting:
- // newstack is doing a scan for us right now. Wait.
-
- case _Grunning:
- // Goroutine running. Try to preempt execution so it can scan itself.
- // The preemption handler (in newstack) does the actual scan.
-
- // Optimization: if there is already a pending preemption request
- // (from the previous loop iteration), don't bother with the atomics.
- if gp.preemptscan && gp.preempt && gp.stackguard0 == stackPreempt {
- break
- }
-
- // Ask for preemption and self scan.
- if castogscanstatus(gp, _Grunning, _Gscanrunning) {
- if !gp.gcscandone {
- gp.preemptscan = true
- gp.preempt = true
- gp.stackguard0 = stackPreempt
- }
- casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
- }
- }
-
- if i == 0 {
- nextYield = nanotime() + yieldDelay
- }
- if nanotime() < nextYield {
- procyield(10)
- } else {
- osyield()
- nextYield = nanotime() + yieldDelay/2
- }
- }
-
- gp.preemptscan = false // cancel scan request if no longer needed
-}
-
-// The GC requests that this routine be moved from a scanmumble state to a mumble state.
-func restartg(gp *g) {
- s := readgstatus(gp)
- switch s {
- default:
- dumpgstatus(gp)
- throw("restartg: unexpected status")
-
- case _Gdead:
- // ok
-
- case _Gscanrunnable,
- _Gscanwaiting,
- _Gscansyscall:
- casfrom_Gscanstatus(gp, s, s&^_Gscan)
- }
-}
-
// stopTheWorld stops all P's from executing goroutines, interrupting
// all goroutines at GC safe points and records reason as the reason
// for the stop. On return, only the current goroutine's P is running.
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 7eac58eb2c..7630888a3d 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -421,7 +421,6 @@ type g struct {
preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
preemptStop bool // transition to _Gpreempted on preemption; otherwise, just deschedule
paniconfault bool // panic (instead of crash) on unexpected fault address
- preemptscan bool // preempted g does scan for gc
gcscandone bool // g has scanned stack; protected by _Gscan bit in status
gcscanvalid bool // false at start of gc cycle, true if G has not run since last scan; TODO: remove?
throwsplit bool // must not split stack
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 3b92c89ff0..2c2a88e6e1 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -916,7 +916,7 @@ func round2(x int32) int32 {
// Stack growth is multiplicative, for constant amortized cost.
//
// g->atomicstatus will be Grunning or Gscanrunning upon entry.
-// If the GC is trying to stop this g then it will set preemptscan to true.
+// If the scheduler is trying to stop this g, then it will set preemptStop.
//
// This must be nowritebarrierrec because it can be called as part of
// stack growth from other nowritebarrierrec functions, but the
@@ -1022,34 +1022,7 @@ func newstack() {
preemptPark(gp) // never returns
}
- // Synchronize with scang.
- casgstatus(gp, _Grunning, _Gwaiting)
- if gp.preemptscan {
- for !castogscanstatus(gp, _Gwaiting, _Gscanwaiting) {
- // Likely to be racing with the GC as
- // it sees a _Gwaiting and does the
- // stack scan. If so, gcworkdone will
- // be set and gcphasework will simply
- // return.
- }
- if !gp.gcscandone {
- // gcw is safe because we're on the
- // system stack.
- gcw := &gp.m.p.ptr().gcw
- scanstack(gp, gcw)
- gp.gcscandone = true
- }
- gp.preemptscan = false
- gp.preempt = false
- casfrom_Gscanstatus(gp, _Gscanwaiting, _Gwaiting)
- // This clears gcscanvalid.
- casgstatus(gp, _Gwaiting, _Grunning)
- gp.stackguard0 = gp.stack.lo + _StackGuard
- gogo(&gp.sched) // never return
- }
-
// Act like goroutine called runtime.Gosched.
- casgstatus(gp, _Gwaiting, _Grunning)
gopreempt_m(gp) // never return
}
--
cgit v1.3-5-g9baa
From 8c5861576a983684faac98c612c9c7e569974ffa Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Fri, 27 Sep 2019 14:13:22 -0400
Subject: runtime: remove g.gcscanvalid
Currently, gcscanvalid is used to resolve a race between attempts to
scan a stack. Now that there's a clear owner of the stack scan
operation, there's no longer any danger of racing or attempting to
scan a stack more than once, so this CL eliminates gcscanvalid.
I double-checked my reasoning by first adding a throw if gcscanvalid
was set in scanstack and verifying that all.bash still passed.
For #10958, #24543.
Fixes #24363.
Change-Id: I76794a5fcda325ed7cfc2b545e2a839b8b3bc713
Reviewed-on: https://go-review.googlesource.com/c/go/+/201139
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/runtime/mgc.go | 3 +--
src/runtime/mgcmark.go | 9 +--------
src/runtime/proc.go | 31 -------------------------------
src/runtime/runtime2.go | 1 -
src/runtime/sizeof_test.go | 2 +-
5 files changed, 3 insertions(+), 43 deletions(-)
(limited to 'src')
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index a7089dd879..4a2ae89391 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -2168,8 +2168,7 @@ func gcResetMarkState() {
// allgs doesn't change.
lock(&allglock)
for _, gp := range allgs {
- gp.gcscandone = false // set to true in gcphasework
- gp.gcscanvalid = false // stack has not been scanned
+ gp.gcscandone = false // set to true in gcphasework
gp.gcAssistBytes = 0
}
unlock(&allglock)
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index adfdaced18..22e70ce157 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -125,8 +125,7 @@ func gcMarkRootCheck() {
fail:
println("gp", gp, "goid", gp.goid,
"status", readgstatus(gp),
- "gcscandone", gp.gcscandone,
- "gcscanvalid", gp.gcscanvalid)
+ "gcscandone", gp.gcscandone)
unlock(&allglock) // Avoid self-deadlock with traceback.
throw("scan missed a g")
}
@@ -674,10 +673,6 @@ func gcFlushBgCredit(scanWork int64) {
//go:nowritebarrier
//go:systemstack
func scanstack(gp *g, gcw *gcWork) {
- if gp.gcscanvalid {
- return
- }
-
if readgstatus(gp)&_Gscan == 0 {
print("runtime:scanstack: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", hex(readgstatus(gp)), "\n")
throw("scanstack - bad status")
@@ -817,8 +812,6 @@ func scanstack(gp *g, gcw *gcWork) {
if state.buf != nil || state.freeBuf != nil {
throw("remaining pointer buffers")
}
-
- gp.gcscanvalid = true
}
// Scan a stack frame: local variables and function arguments/results.
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 9e40bc8c94..9a553a5f88 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -710,18 +710,6 @@ func readgstatus(gp *g) uint32 {
return atomic.Load(&gp.atomicstatus)
}
-// Ownership of gcscanvalid:
-//
-// If gp is running (meaning status == _Grunning or _Grunning|_Gscan),
-// then gp owns gp.gcscanvalid, and other goroutines must not modify it.
-//
-// Otherwise, a second goroutine can lock the scan state by setting _Gscan
-// in the status bit and then modify gcscanvalid, and then unlock the scan state.
-//
-// Note that the first condition implies an exception to the second:
-// if a second goroutine changes gp's status to _Grunning|_Gscan,
-// that second goroutine still does not have the right to modify gcscanvalid.
-
// The Gscanstatuses are acting like locks and this releases them.
// If it proves to be a performance hit we should be able to make these
// simple atomic stores but for now we are going to throw if
@@ -781,17 +769,6 @@ func casgstatus(gp *g, oldval, newval uint32) {
})
}
- if oldval == _Grunning && gp.gcscanvalid {
- // If oldvall == _Grunning, then the actual status must be
- // _Grunning or _Grunning|_Gscan; either way,
- // we own gp.gcscanvalid, so it's safe to read.
- // gp.gcscanvalid must not be true when we are running.
- systemstack(func() {
- print("runtime: casgstatus ", hex(oldval), "->", hex(newval), " gp.status=", hex(gp.atomicstatus), " gp.gcscanvalid=true\n")
- throw("casgstatus")
- })
- }
-
// See https://golang.org/cl/21503 for justification of the yield delay.
const yieldDelay = 5 * 1000
var nextYield int64
@@ -814,9 +791,6 @@ func casgstatus(gp *g, oldval, newval uint32) {
nextYield = nanotime() + yieldDelay/2
}
}
- if newval == _Grunning {
- gp.gcscanvalid = false
- }
}
// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
@@ -1585,7 +1559,6 @@ func oneNewExtraM() {
gp.syscallpc = gp.sched.pc
gp.syscallsp = gp.sched.sp
gp.stktopsp = gp.sched.sp
- gp.gcscanvalid = true
// malg returns status as _Gidle. Change to _Gdead before
// adding to allg where GC can see it. We use _Gdead to hide
// this from tracebacks and stack scans since it isn't a
@@ -2815,9 +2788,6 @@ func goexit0(gp *g) {
gp.gcAssistBytes = 0
}
- // Note that gp's stack scan is now "valid" because it has no
- // stack.
- gp.gcscanvalid = true
dropg()
if GOARCH == "wasm" { // no threads yet on wasm
@@ -3462,7 +3432,6 @@ func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerp
if isSystemGoroutine(newg, false) {
atomic.Xadd(&sched.ngsys, +1)
}
- newg.gcscanvalid = false
casgstatus(newg, _Gdead, _Grunnable)
if _p_.goidcache == _p_.goidcacheend {
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 7630888a3d..a146f47446 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -422,7 +422,6 @@ type g struct {
preemptStop bool // transition to _Gpreempted on preemption; otherwise, just deschedule
paniconfault bool // panic (instead of crash) on unexpected fault address
gcscandone bool // g has scanned stack; protected by _Gscan bit in status
- gcscanvalid bool // false at start of gc cycle, true if G has not run since last scan; TODO: remove?
throwsplit bool // must not split stack
raceignore int8 // ignore race detection events
sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine
diff --git a/src/runtime/sizeof_test.go b/src/runtime/sizeof_test.go
index 852244d425..406a38aad9 100644
--- a/src/runtime/sizeof_test.go
+++ b/src/runtime/sizeof_test.go
@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {runtime.G{}, 216, 376}, // g, but exported for testing
+ {runtime.G{}, 212, 368}, // g, but exported for testing
}
for _, tt := range tests {
--
cgit v1.3-5-g9baa
From 36a432f27bbcc65fb03845ebe5e4a3db6f4cc189 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Wed, 3 Apr 2019 14:00:12 -0400
Subject: runtime: make copystack/sudog synchronization more explicit
When we copy a stack of a goroutine blocked in a channel operation, we
have to be very careful because other goroutines may be writing to
that goroutine's stack. To handle this, stack copying acquires the
locks for the channels a goroutine is waiting on.
One complication is that stack growth may happen while a goroutine
holds these locks, in which case stack copying must *not* acquire
these locks because that would self-deadlock.
Currently, stack growth never acquires these locks because stack
growth only happens when a goroutine is running, which means it's
either not blocking on a channel or it's holding the channel locks
already. Stack shrinking always acquires these locks because shrinking
happens asynchronously, so the goroutine is never running, so there
are either no locks or they've been released by the goroutine.
However, we're about to change when stack shrinking can happen, which
is going to break the current rules. Rather than find a new way to
derive whether to acquire these locks or not, this CL simply adds a
flag to the g struct that indicates that stack copying should acquire
channel locks. This flag is set while the goroutine is blocked on a
channel op.
For #10958, #24543.
Change-Id: Ia2ac8831b1bfda98d39bb30285e144c4f7eaf9ab
Reviewed-on: https://go-review.googlesource.com/c/go/+/172982
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Michael Knyszek
---
src/runtime/chan.go | 14 ++++++++++--
src/runtime/runtime2.go | 54 +++++++++++++++++++++++++---------------------
src/runtime/select.go | 4 ++++
src/runtime/sizeof_test.go | 2 +-
src/runtime/stack.go | 30 ++++++++++----------------
5 files changed, 58 insertions(+), 46 deletions(-)
(limited to 'src')
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 93afe90dad..677af99eac 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -249,7 +249,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
gp.waiting = mysg
gp.param = nil
c.sendq.enqueue(mysg)
- goparkunlock(&c.lock, waitReasonChanSend, traceEvGoBlockSend, 3)
+ gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceEvGoBlockSend, 2)
// Ensure the value being sent is kept alive until the
// receiver copies it out. The sudog has a pointer to the
// stack object, but sudogs aren't considered as roots of the
@@ -261,6 +261,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
throw("G waiting list is corrupted")
}
gp.waiting = nil
+ gp.activeStackChans = false
if gp.param == nil {
if c.closed == 0 {
throw("chansend: spurious wakeup")
@@ -559,13 +560,14 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
mysg.c = c
gp.param = nil
c.recvq.enqueue(mysg)
- goparkunlock(&c.lock, waitReasonChanReceive, traceEvGoBlockRecv, 3)
+ gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanReceive, traceEvGoBlockRecv, 2)
// someone woke us up
if mysg != gp.waiting {
throw("G waiting list is corrupted")
}
gp.waiting = nil
+ gp.activeStackChans = false
if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2)
}
@@ -632,6 +634,14 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
goready(gp, skip+1)
}
+func chanparkcommit(gp *g, chanLock unsafe.Pointer) bool {
+ // There are unlocked sudogs that point into gp's stack. Stack
+ // copying must lock the channels of those sudogs.
+ gp.activeStackChans = true
+ unlock((*mutex)(chanLock))
+ return true
+}
+
// compiler implements
//
// select {
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index a146f47446..bf56466e08 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -404,30 +404,36 @@ type g struct {
stackguard0 uintptr // offset known to liblink
stackguard1 uintptr // offset known to liblink
- _panic *_panic // innermost panic - offset known to liblink
- _defer *_defer // innermost defer
- m *m // current m; offset known to arm liblink
- sched gobuf
- syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
- syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
- stktopsp uintptr // expected sp at top of stack, to check in traceback
- param unsafe.Pointer // passed parameter on wakeup
- atomicstatus uint32
- stackLock uint32 // sigprof/scang lock; TODO: fold in to atomicstatus
- goid int64
- schedlink guintptr
- waitsince int64 // approx time when the g become blocked
- waitreason waitReason // if status==Gwaiting
- preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
- preemptStop bool // transition to _Gpreempted on preemption; otherwise, just deschedule
- paniconfault bool // panic (instead of crash) on unexpected fault address
- gcscandone bool // g has scanned stack; protected by _Gscan bit in status
- throwsplit bool // must not split stack
- raceignore int8 // ignore race detection events
- sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine
- sysexitticks int64 // cputicks when syscall has returned (for tracing)
- traceseq uint64 // trace event sequencer
- tracelastp puintptr // last P emitted an event for this goroutine
+ _panic *_panic // innermost panic - offset known to liblink
+ _defer *_defer // innermost defer
+ m *m // current m; offset known to arm liblink
+ sched gobuf
+ syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
+ syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
+ stktopsp uintptr // expected sp at top of stack, to check in traceback
+ param unsafe.Pointer // passed parameter on wakeup
+ atomicstatus uint32
+ stackLock uint32 // sigprof/scang lock; TODO: fold in to atomicstatus
+ goid int64
+ schedlink guintptr
+ waitsince int64 // approx time when the g become blocked
+ waitreason waitReason // if status==Gwaiting
+ preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
+ preemptStop bool // transition to _Gpreempted on preemption; otherwise, just deschedule
+ paniconfault bool // panic (instead of crash) on unexpected fault address
+ gcscandone bool // g has scanned stack; protected by _Gscan bit in status
+ throwsplit bool // must not split stack
+ // activeStackChans indicates that there are unlocked channels
+ // pointing into this goroutine's stack. If true, stack
+ // copying needs to acquire channel locks to protect these
+ // areas of the stack.
+ activeStackChans bool
+
+ raceignore int8 // ignore race detection events
+ sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine
+ sysexitticks int64 // cputicks when syscall has returned (for tracing)
+ traceseq uint64 // trace event sequencer
+ tracelastp puintptr // last P emitted an event for this goroutine
lockedm muintptr
sig uint32
writebuf []byte
diff --git a/src/runtime/select.go b/src/runtime/select.go
index d2c5a03a1a..8033b6512f 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -75,6 +75,9 @@ func selunlock(scases []scase, lockorder []uint16) {
}
func selparkcommit(gp *g, _ unsafe.Pointer) bool {
+ // There are unlocked sudogs that point into gp's stack. Stack
+ // copying must lock the channels of those sudogs.
+ gp.activeStackChans = true
// This must not access gp's stack (see gopark). In
// particular, it must not access the *hselect. That's okay,
// because by the time this is called, gp.waiting has all
@@ -311,6 +314,7 @@ loop:
// wait for someone to wake us up
gp.param = nil
gopark(selparkcommit, nil, waitReasonSelect, traceEvGoBlockSelect, 1)
+ gp.activeStackChans = false
sellock(scases, lockorder)
diff --git a/src/runtime/sizeof_test.go b/src/runtime/sizeof_test.go
index 406a38aad9..852244d425 100644
--- a/src/runtime/sizeof_test.go
+++ b/src/runtime/sizeof_test.go
@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {runtime.G{}, 212, 368}, // g, but exported for testing
+ {runtime.G{}, 216, 376}, // g, but exported for testing
}
for _, tt := range tests {
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 2c2a88e6e1..e47f12a8dc 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -786,10 +786,6 @@ func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr {
}
// Lock channels to prevent concurrent send/receive.
- // It's important that we *only* do this for async
- // copystack; otherwise, gp may be in the middle of
- // putting itself on wait queues and this would
- // self-deadlock.
var lastc *hchan
for sg := gp.waiting; sg != nil; sg = sg.waitlink {
if sg.c != lastc {
@@ -826,12 +822,7 @@ func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr {
// Copies gp's stack to a new stack of a different size.
// Caller must have changed gp status to Gcopystack.
-//
-// If sync is true, this is a self-triggered stack growth and, in
-// particular, no other G may be writing to gp's stack (e.g., via a
-// channel operation). If sync is false, copystack protects against
-// concurrent channel operations.
-func copystack(gp *g, newsize uintptr, sync bool) {
+func copystack(gp *g, newsize uintptr) {
if gp.syscallsp != 0 {
throw("stack growth not allowed in system call")
}
@@ -857,15 +848,16 @@ func copystack(gp *g, newsize uintptr, sync bool) {
// Adjust sudogs, synchronizing with channel ops if necessary.
ncopy := used
- if sync {
+ if !gp.activeStackChans {
adjustsudogs(gp, &adjinfo)
} else {
- // sudogs can point in to the stack. During concurrent
- // shrinking, these areas may be written to. Find the
- // highest such pointer so we can handle everything
- // there and below carefully. (This shouldn't be far
- // from the bottom of the stack, so there's little
- // cost in handling everything below it carefully.)
+ // sudogs may be pointing in to the stack and gp has
+ // released channel locks, so other goroutines could
+ // be writing to gp's stack. Find the highest such
+ // pointer so we can handle everything there and below
+ // carefully. (This shouldn't be far from the bottom
+ // of the stack, so there's little cost in handling
+ // everything below it carefully.)
adjinfo.sghi = findsghi(gp, old)
// Synchronize with channel ops and copy the part of
@@ -1040,7 +1032,7 @@ func newstack() {
// The concurrent GC will not scan the stack while we are doing the copy since
// the gp is in a Gcopystack status.
- copystack(gp, newsize, true)
+ copystack(gp, newsize)
if stackDebug >= 1 {
print("stack grow done\n")
}
@@ -1120,7 +1112,7 @@ func shrinkstack(gp *g) {
print("shrinking stack ", oldsize, "->", newsize, "\n")
}
- copystack(gp, newsize, false)
+ copystack(gp, newsize)
}
// freeStackSpans frees unused stack spans at the end of GC.
--
cgit v1.3-5-g9baa
From 60586034713cc94477868fb6911f34cfcc6a1ba4 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Fri, 27 Sep 2019 14:34:05 -0400
Subject: runtime: only shrink stacks at synchronous safe points
We're about to introduce asynchronous safe points, where we won't have
precise pointer maps for all stack frames. That's okay for scanning
the stack (conservatively), but not for shrinking the stack.
Hence, this CL prepares for this by only shrinking the stack as part
of the stack scan if the goroutine is stopped at a synchronous safe
point. Otherwise, it queues up the stack shrink for the next
synchronous safe point.
We already have one condition under which we can't shrink the stack
for very similar reasons: syscalls. Currently, we just give up on
shrinking the stack if it's in a syscall. But with this mechanism, we
defer that stack shrink until the next synchronous safe point.
For #10958, #24543.
Change-Id: Ifa1dec6f33fdf30f9067be2ce3f7ab8a7f62ce38
Reviewed-on: https://go-review.googlesource.com/c/go/+/201438
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/runtime/mgcmark.go | 13 +++++++++++--
src/runtime/runtime2.go | 13 ++++++++-----
src/runtime/stack.go | 43 ++++++++++++++++++++++++++++++++-----------
3 files changed, 51 insertions(+), 18 deletions(-)
(limited to 'src')
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index 22e70ce157..338983424c 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -667,6 +667,10 @@ func gcFlushBgCredit(scanWork int64) {
// scanstack scans gp's stack, greying all pointers found on the stack.
//
+// scanstack will also shrink the stack if it is safe to do so. If it
+// is not, it schedules a stack shrink for the next synchronous safe
+// point.
+//
// scanstack is marked go:systemstack because it must not be preempted
// while using a workbuf.
//
@@ -695,8 +699,13 @@ func scanstack(gp *g, gcw *gcWork) {
throw("can't scan our own stack")
}
- // Shrink the stack if not much of it is being used.
- shrinkstack(gp)
+ if isShrinkStackSafe(gp) {
+ // Shrink the stack if not much of it is being used.
+ shrinkstack(gp)
+ } else {
+ // Otherwise, shrink the stack at the next sync safe point.
+ gp.preemptShrink = true
+ }
var state stackScanState
state.stack = gp.stack
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index bf56466e08..eecc6a78ac 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -418,11 +418,14 @@ type g struct {
schedlink guintptr
waitsince int64 // approx time when the g become blocked
waitreason waitReason // if status==Gwaiting
- preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
- preemptStop bool // transition to _Gpreempted on preemption; otherwise, just deschedule
- paniconfault bool // panic (instead of crash) on unexpected fault address
- gcscandone bool // g has scanned stack; protected by _Gscan bit in status
- throwsplit bool // must not split stack
+
+ preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
+ preemptStop bool // transition to _Gpreempted on preemption; otherwise, just deschedule
+ preemptShrink bool // shrink stack at synchronous safe point
+
+ paniconfault bool // panic (instead of crash) on unexpected fault address
+ gcscandone bool // g has scanned stack; protected by _Gscan bit in status
+ throwsplit bool // must not split stack
// activeStackChans indicates that there are unlocked channels
// pointing into this goroutine's stack. If true, stack
// copying needs to acquire channel locks to protect these
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index e47f12a8dc..825826cacd 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -1010,6 +1010,13 @@ func newstack() {
throw("runtime: g is running but p is not")
}
+ if gp.preemptShrink {
+ // We're at a synchronous safe point now, so
+ // do the pending stack shrink.
+ gp.preemptShrink = false
+ shrinkstack(gp)
+ }
+
if gp.preemptStop {
preemptPark(gp) // never returns
}
@@ -1057,16 +1064,36 @@ func gostartcallfn(gobuf *gobuf, fv *funcval) {
gostartcall(gobuf, fn, unsafe.Pointer(fv))
}
+// isShrinkStackSafe returns whether it's safe to attempt to shrink
+// gp's stack. Shrinking the stack is only safe when we have precise
+// pointer maps for all frames on the stack.
+func isShrinkStackSafe(gp *g) bool {
+ // We can't copy the stack if we're in a syscall.
+ // The syscall might have pointers into the stack and
+ // often we don't have precise pointer maps for the innermost
+ // frames.
+ return gp.syscallsp == 0
+}
+
// Maybe shrink the stack being used by gp.
-// Called at garbage collection time.
-// gp must be stopped, but the world need not be.
+//
+// gp must be stopped and we must own its stack. It may be in
+// _Grunning, but only if this is our own user G.
func shrinkstack(gp *g) {
- gstatus := readgstatus(gp)
if gp.stack.lo == 0 {
throw("missing stack in shrinkstack")
}
- if gstatus&_Gscan == 0 {
- throw("bad status in shrinkstack")
+ if s := readgstatus(gp); s&_Gscan == 0 {
+ // We don't own the stack via _Gscan. We could still
+ // own it if this is our own user G and we're on the
+ // system stack.
+ if !(gp == getg().m.curg && getg() != getg().m.curg && s == _Grunning) {
+ // We don't own the stack.
+ throw("bad status in shrinkstack")
+ }
+ }
+ if !isShrinkStackSafe(gp) {
+ throw("shrinkstack at bad time")
}
// Check for self-shrinks while in a libcall. These may have
// pointers into the stack disguised as uintptrs, but these
@@ -1102,12 +1129,6 @@ func shrinkstack(gp *g) {
return
}
- // We can't copy the stack if we're in a syscall.
- // The syscall might have pointers into the stack.
- if gp.syscallsp != 0 {
- return
- }
-
if stackDebug > 0 {
print("shrinking stack ", oldsize, "->", newsize, "\n")
}
--
cgit v1.3-5-g9baa
From d1969015b4ac29be4f518b94817d3f525380639d Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Fri, 4 Oct 2019 18:54:00 -0400
Subject: runtime: abstract M preemption check into a function
We check whether an M is preemptible in a surprising number of places.
Put it in one function.
For #10958, #24543.
Change-Id: I305090fdb1ea7f7a55ffe25851c1e35012d0d06c
Reviewed-on: https://go-review.googlesource.com/c/go/+/201439
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/runtime/mgcwork.go | 10 +++++-----
src/runtime/preempt.go | 9 +++++++++
src/runtime/proc.go | 2 +-
src/runtime/stack.go | 2 +-
4 files changed, 16 insertions(+), 7 deletions(-)
(limited to 'src')
diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go
index f2c16d7d8c..927b06c3f9 100644
--- a/src/runtime/mgcwork.go
+++ b/src/runtime/mgcwork.go
@@ -126,12 +126,12 @@ func (w *gcWork) checkPut(ptr uintptr, ptrs []uintptr) {
if debugCachedWork {
alreadyFailed := w.putGen == w.pauseGen
w.putGen = w.pauseGen
- if m := getg().m; m.locks > 0 || m.mallocing != 0 || m.preemptoff != "" || m.p.ptr().status != _Prunning {
+ if !canPreemptM(getg().m) {
// If we were to spin, the runtime may
- // deadlock: the condition above prevents
- // preemption (see newstack), which could
- // prevent gcMarkDone from finishing the
- // ragged barrier and releasing the spin.
+ // deadlock. Since we can't be preempted, the
+ // spin could prevent gcMarkDone from
+ // finishing the ragged barrier, which is what
+ // releases us from the spin.
return
}
for atomic.Load(&gcWorkPauseGen) == w.pauseGen {
diff --git a/src/runtime/preempt.go b/src/runtime/preempt.go
index 0565fd6360..96eaa3488b 100644
--- a/src/runtime/preempt.go
+++ b/src/runtime/preempt.go
@@ -223,3 +223,12 @@ func resumeG(state suspendGState) {
ready(gp, 0, true)
}
}
+
+// canPreemptM reports whether mp is in a state that is safe to preempt.
+//
+// It is nosplit because it has nosplit callers.
+//
+//go:nosplit
+func canPreemptM(mp *m) bool {
+ return mp.locks == 0 && mp.mallocing == 0 && mp.preemptoff == "" && mp.p.ptr().status == _Prunning
+}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 9a553a5f88..60a15c1e9c 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -2703,7 +2703,7 @@ func gosched_m(gp *g) {
// goschedguarded is a forbidden-states-avoided version of gosched_m
func goschedguarded_m(gp *g) {
- if gp.m.locks != 0 || gp.m.mallocing != 0 || gp.m.preemptoff != "" || gp.m.p.ptr().status != _Prunning {
+ if !canPreemptM(gp.m) {
gogo(&gp.sched) // never return
}
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 825826cacd..ecefce1e32 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -975,7 +975,7 @@ func newstack() {
// it needs a lock held by the goroutine), that small preemption turns
// into a real deadlock.
if preempt {
- if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.ptr().status != _Prunning {
+ if !canPreemptM(thisg.m) {
// Let the goroutine keep running for now.
// gp->preempt is set, so it will be preempted next time.
gp.stackguard0 = gp.stack.lo + _StackGuard
--
cgit v1.3-5-g9baa
From 80315322f3068123ab98632c55ee4bc9d7a03930 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le
Date: Tue, 22 Oct 2019 15:40:51 +0700
Subject: runtime: simplify findObject bad pointer checking condition
Factor out case s == nil, make the code cleaner and easier to read.
Change-Id: I63f52e14351c0a0d20a611b1fe10fdc0d4947d96
Reviewed-on: https://go-review.googlesource.com/c/go/+/202498
Run-TryBot: Cuong Manh Le
TryBot-Result: Gobot Gobot
Reviewed-by: Austin Clements
Reviewed-by: Keith Randall
---
src/runtime/mbitmap.go | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
(limited to 'src')
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index 30ec5f1cc9..7f9f71842d 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -361,12 +361,15 @@ func heapBitsForAddr(addr uintptr) (h heapBits) {
// was found. These are used for error reporting.
func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex uintptr) {
s = spanOf(p)
+ // If s is nil, the virtual address has never been part of the heap.
+ // This pointer may be to some mmap'd region, so we allow it.
+ if s == nil {
+ return
+ }
// If p is a bad pointer, it may not be in s's bounds.
- if s == nil || p < s.base() || p >= s.limit || s.state != mSpanInUse {
- if s == nil || s.state == mSpanManual {
- // If s is nil, the virtual address has never been part of the heap.
- // This pointer may be to some mmap'd region, so we allow it.
- // Pointers into stacks are also ok, the runtime manages these explicitly.
+ if p < s.base() || p >= s.limit || s.state != mSpanInUse {
+ // Pointers into stacks are also ok, the runtime manages these explicitly.
+ if s.state == mSpanManual {
return
}
--
cgit v1.3-5-g9baa
From 813d8e886208e5e001df3b55e8bc1c65ca4249ff Mon Sep 17 00:00:00 2001
From: Cuong Manh Le
Date: Wed, 23 Oct 2019 14:28:55 +0700
Subject: runtime: factor out debug.invalidptr case in findObject
This helps keeping findObject's frame small.
Updates #35068
Change-Id: I1b8c1fcc5831944c86f1a30ed2f2d867a5f2b242
Reviewed-on: https://go-review.googlesource.com/c/go/+/202797
Run-TryBot: Cuong Manh Le
TryBot-Result: Gobot Gobot
Reviewed-by: Austin Clements
---
src/runtime/mbitmap.go | 50 +++++++++++++++++++++++++++-----------------------
1 file changed, 27 insertions(+), 23 deletions(-)
(limited to 'src')
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index 7f9f71842d..68a22690d2 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -349,6 +349,32 @@ func heapBitsForAddr(addr uintptr) (h heapBits) {
return
}
+// badPointer throws bad pointer in heap panic.
+func badPointer(s *mspan, p, refBase, refOff uintptr) {
+ // Typically this indicates an incorrect use
+ // of unsafe or cgo to store a bad pointer in
+ // the Go heap. It may also indicate a runtime
+ // bug.
+ //
+ // TODO(austin): We could be more aggressive
+ // and detect pointers to unallocated objects
+ // in allocated spans.
+ printlock()
+ print("runtime: pointer ", hex(p))
+ if s.state != mSpanInUse {
+ print(" to unallocated span")
+ } else {
+ print(" to unused region of span")
+ }
+ print(" span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", s.state, "\n")
+ if refBase != 0 {
+ print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n")
+ gcDumpObject("object", refBase, refOff)
+ }
+ getg().m.traceback = 2
+ throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)")
+}
+
// findObject returns the base address for the heap object containing
// the address p, the object's span, and the index of the object in s.
// If p does not point into a heap object, it returns base == 0.
@@ -372,32 +398,10 @@ func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex ui
if s.state == mSpanManual {
return
}
-
// The following ensures that we are rigorous about what data
// structures hold valid pointers.
if debug.invalidptr != 0 {
- // Typically this indicates an incorrect use
- // of unsafe or cgo to store a bad pointer in
- // the Go heap. It may also indicate a runtime
- // bug.
- //
- // TODO(austin): We could be more aggressive
- // and detect pointers to unallocated objects
- // in allocated spans.
- printlock()
- print("runtime: pointer ", hex(p))
- if s.state != mSpanInUse {
- print(" to unallocated span")
- } else {
- print(" to unused region of span")
- }
- print(" span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", s.state, "\n")
- if refBase != 0 {
- print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n")
- gcDumpObject("object", refBase, refOff)
- }
- getg().m.traceback = 2
- throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)")
+ badPointer(s, p, refBase, refOff)
}
return
}
--
cgit v1.3-5-g9baa
From 66f78e9d885e9a8ed7f8d2432d9f08bb586dd7cb Mon Sep 17 00:00:00 2001
From: Cuong Manh Le
Date: Wed, 23 Oct 2019 14:31:29 +0700
Subject: runtime: mark findObject nosplit
findObject takes the pointer argument as uintptr. If the pointer is to
the local stack and calling findObject happens to require the stack to
be reallocated, then spanOf is called for the old pointer.
Marking findObject as nosplit fixes the issue.
Fixes #35068
Change-Id: I029d36f9c23f91812f18f98839edf02e0ba4082e
Reviewed-on: https://go-review.googlesource.com/c/go/+/202798
Run-TryBot: Cuong Manh Le
TryBot-Result: Gobot Gobot
Reviewed-by: Austin Clements
---
src/runtime/mbitmap.go | 4 ++++
1 file changed, 4 insertions(+)
(limited to 'src')
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index 68a22690d2..d131bab600 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -385,6 +385,10 @@ func badPointer(s *mspan, p, refBase, refOff uintptr) {
// refBase and refOff optionally give the base address of the object
// in which the pointer p was found and the byte offset at which it
// was found. These are used for error reporting.
+//
+// It is nosplit so it is safe for p to be a pointer to the current goroutine's stack.
+// Since p is a uintptr, it would not be adjusted if the stack were to move.
+//go:nosplit
func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex uintptr) {
s = spanOf(p)
// If s is nil, the virtual address has never been part of the heap.
--
cgit v1.3-5-g9baa
From 06bdd52f7540eca9e3ade6e78234d00703f3ee23 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills"
Date: Fri, 25 Oct 2019 15:37:00 -0400
Subject: os: use an actual RemoveAll failure in
TestRemoveAllWithMoreErrorThanReqSize
Previously we injected an error, and the injection points were
(empirically) not realistic on some platforms.
Instead, we now make the directory read-only, which (on most
platforms) suffices to prevent the removal of its files.
Fixes #35117
Updates #29921
Change-Id: Ica4e2818566f8c14df3eed7c3b8de5c0abeb6963
Reviewed-on: https://go-review.googlesource.com/c/go/+/203502
Reviewed-by: Ian Lance Taylor
Reviewed-by: Brad Fitzpatrick
---
src/os/export_test.go | 1 -
src/os/removeall_at.go | 1 -
src/os/removeall_noat.go | 1 -
src/os/removeall_test.go | 50 ++++++++++++++++++++++++++++++++----------------
4 files changed, 34 insertions(+), 19 deletions(-)
(limited to 'src')
diff --git a/src/os/export_test.go b/src/os/export_test.go
index d17d5e6230..812432cee4 100644
--- a/src/os/export_test.go
+++ b/src/os/export_test.go
@@ -9,4 +9,3 @@ package os
var Atime = atime
var LstatP = &lstat
var ErrWriteAtInAppendMode = errWriteAtInAppendMode
-var RemoveAllTestHook = &removeAllTestHook
diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go
index bc632f5a75..e619851f9c 100644
--- a/src/os/removeall_at.go
+++ b/src/os/removeall_at.go
@@ -153,7 +153,6 @@ func removeAllFrom(parent *File, base string) error {
// Remove the directory itself.
unlinkError := unix.Unlinkat(parentFd, base, unix.AT_REMOVEDIR)
- unlinkError = removeAllTestHook(unlinkError)
if unlinkError == nil || IsNotExist(unlinkError) {
return nil
}
diff --git a/src/os/removeall_noat.go b/src/os/removeall_noat.go
index a0694fa4ce..32673c0ab0 100644
--- a/src/os/removeall_noat.go
+++ b/src/os/removeall_noat.go
@@ -124,7 +124,6 @@ func removeAll(path string) error {
// Remove directory.
err1 := Remove(path)
- err1 = removeAllTestHook(err1)
if err1 == nil || IsNotExist(err1) {
return nil
}
diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go
index 8700b6af17..1fa0dcdd33 100644
--- a/src/os/removeall_test.go
+++ b/src/os/removeall_test.go
@@ -5,7 +5,6 @@
package os_test
import (
- "errors"
"fmt"
"io/ioutil"
. "os"
@@ -413,14 +412,6 @@ func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) {
t.Skip("skipping in short mode")
}
- defer func(oldHook func(error) error) {
- *RemoveAllTestHook = oldHook
- }(*RemoveAllTestHook)
-
- *RemoveAllTestHook = func(err error) error {
- return errors.New("error from RemoveAllTestHook")
- }
-
tmpDir, err := ioutil.TempDir("", "TestRemoveAll-")
if err != nil {
t.Fatal(err)
@@ -429,7 +420,7 @@ func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) {
path := filepath.Join(tmpDir, "_TestRemoveAllWithMoreErrorThanReqSize_")
- // Make directory with 1025 files and remove.
+ // Make directory with 1025 read-only files.
if err := MkdirAll(path, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
@@ -442,13 +433,40 @@ func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) {
fd.Close()
}
- // This call should not hang
- if err := RemoveAll(path); err == nil {
- t.Fatal("Want error from RemoveAllTestHook, got nil")
+ // Make the parent directory read-only. On some platforms, this is what
+ // prevents os.Remove from removing the files within that directory.
+ if err := Chmod(path, 0555); err != nil {
+ t.Fatal(err)
}
+ defer Chmod(path, 0755)
- // We hook to inject error, but the actual files must be deleted
- if _, err := Lstat(path); err == nil {
- t.Fatal("directory must be deleted even with removeAllTetHook run")
+ // This call should not hang, even on a platform that disallows file deletion
+ // from read-only directories.
+ err = RemoveAll(path)
+
+ if Getuid() == 0 {
+ // On many platforms, root can remove files from read-only directories.
+ return
+ }
+ if err == nil {
+ t.Fatal("RemoveAll() = nil; want error")
+ }
+
+ dir, err := Open(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer dir.Close()
+
+ if runtime.GOOS == "windows" {
+ // Marking a directory in Windows does not prevent the os package from
+ // creating or removing files within it.
+ // (See https://golang.org/issue/35042.)
+ return
+ }
+
+ names, _ := dir.Readdirnames(1025)
+ if len(names) < 1025 {
+ t.Fatalf("RemoveAll() unexpectedly removed %d read-only files from that directory", 1025-len(names))
}
}
--
cgit v1.3-5-g9baa
From 3706cd85d37ec554821393eb49cb3c88edf9308a Mon Sep 17 00:00:00 2001
From: Vivek V
Date: Fri, 25 Oct 2019 07:14:18 +0000
Subject: debug/dwarf: call strings.EqualFold instead of calling Lower twice
Change-Id: I8dcb425c37a067277549ba3bda6a21206459890a
GitHub-Last-Rev: dc51b9b425ca51cd0a4ac494d4c7a3c0e2306951
GitHub-Pull-Request: golang/go#35132
Reviewed-on: https://go-review.googlesource.com/c/go/+/203097
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/debug/dwarf/line.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/debug/dwarf/line.go b/src/debug/dwarf/line.go
index 1cd9dd98cf..7692f05552 100644
--- a/src/debug/dwarf/line.go
+++ b/src/debug/dwarf/line.go
@@ -806,7 +806,7 @@ func pathJoin(dirname, filename string) string {
// DOS-style path.
drive2, filename := splitDrive(filename)
if drive2 != "" {
- if strings.ToLower(drive) != strings.ToLower(drive2) {
+ if !strings.EqualFold(drive, drive2) {
// Different drives. There's not much we can
// do here, so just ignore the directory.
return drive2 + filename
--
cgit v1.3-5-g9baa
From 334291d1f629fb027bfcd7bff6d30e01dd9bf4c5 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Thu, 3 Oct 2019 10:19:38 -0400
Subject: runtime: M-targeted signals for Linux
We'll add a test once all of the POSIX platforms are done.
For #10958, #24543.
Change-Id: If7e3f14e8391791364877629bf415d9f8e788b0a
Reviewed-on: https://go-review.googlesource.com/c/go/+/201401
Run-TryBot: Austin Clements
Reviewed-by: Cherry Zhang
---
src/runtime/os_linux.go | 12 +++++++++++-
src/runtime/sys_linux_386.s | 14 ++++++++++++++
src/runtime/sys_linux_amd64.s | 14 ++++++++++++++
src/runtime/sys_linux_arm.s | 14 ++++++++++++++
src/runtime/sys_linux_arm64.s | 14 ++++++++++++++
src/runtime/sys_linux_mips64x.s | 14 ++++++++++++++
src/runtime/sys_linux_mipsx.s | 14 ++++++++++++++
src/runtime/sys_linux_ppc64x.s | 12 ++++++++++++
src/runtime/sys_linux_s390x.s | 14 ++++++++++++++
9 files changed, 121 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go
index b1ddf53dd1..20b947f250 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -332,7 +332,9 @@ func gettid() uint32
func minit() {
minitSignals()
- // for debuggers, in case cgo created the thread
+ // Cgo-created threads and the bootstrap m are missing a
+ // procid. We need this for asynchronous preemption and its
+ // useful in debuggers.
getg().m.procid = uint64(gettid())
}
@@ -454,3 +456,11 @@ func sysSigaction(sig uint32, new, old *sigactiont) {
// rt_sigaction is implemented in assembly.
//go:noescape
func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
+
+func getpid() int
+func tgkill(tgid, tid, sig int)
+
+// signalM sends a signal to mp.
+func signalM(mp *m, sig int) {
+ tgkill(getpid(), int(mp.procid), sig)
+}
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 4b440b13cb..373d9d3bc2 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -188,6 +188,20 @@ TEXT runtime·raiseproc(SB),NOSPLIT,$12
INVOKE_SYSCALL
RET
+TEXT ·getpid(SB),NOSPLIT,$0-4
+ MOVL $SYS_getpid, AX
+ INVOKE_SYSCALL
+ MOVL AX, ret+0(FP)
+ RET
+
+TEXT ·tgkill(SB),NOSPLIT,$0
+ MOVL $SYS_tgkill, AX
+ MOVL tgid+0(FP), BX
+ MOVL tid+4(FP), CX
+ MOVL sig+8(FP), DX
+ INVOKE_SYSCALL
+ RET
+
TEXT runtime·setitimer(SB),NOSPLIT,$0-12
MOVL $SYS_setittimer, AX
MOVL mode+0(FP), BX
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 0728d1766e..d16060f6fa 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -171,6 +171,20 @@ TEXT runtime·raiseproc(SB),NOSPLIT,$0
SYSCALL
RET
+TEXT ·getpid(SB),NOSPLIT,$0-8
+ MOVL $SYS_getpid, AX
+ SYSCALL
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT ·tgkill(SB),NOSPLIT,$0
+ MOVQ tgid+0(FP), DI
+ MOVQ tid+8(FP), SI
+ MOVQ sig+16(FP), DX
+ MOVL $SYS_tgkill, AX
+ SYSCALL
+ RET
+
TEXT runtime·setitimer(SB),NOSPLIT,$0-24
MOVL mode+0(FP), DI
MOVQ new+8(FP), SI
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 9a9e1c92c7..a787440a15 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -172,6 +172,20 @@ TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
SWI $0
RET
+TEXT ·getpid(SB),NOSPLIT,$0-4
+ MOVW $SYS_getpid, R7
+ SWI $0
+ MOVW R0, ret+0(FP)
+ RET
+
+TEXT ·tgkill(SB),NOSPLIT,$0-12
+ MOVW tgid+0(FP), R0
+ MOVW tid+4(FP), R1
+ MOVW sig+8(FP), R2
+ MOVW $SYS_tgkill, R7
+ SWI $0
+ RET
+
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVW addr+0(FP), R0
MOVW n+4(FP), R1
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index a77be98739..e0d681ebf1 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -175,6 +175,20 @@ TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
SVC
RET
+TEXT ·getpid(SB),NOSPLIT|NOFRAME,$0-8
+ MOVD $SYS_getpid, R8
+ SVC
+ MOVD R0, ret+0(FP)
+ RET
+
+TEXT ·tgkill(SB),NOSPLIT,$0-24
+ MOVD tgid+0(FP), R0
+ MOVD tid+8(FP), R1
+ MOVD sig+16(FP), R2
+ MOVD $SYS_tgkill, R8
+ SVC
+ RET
+
TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
MOVW mode+0(FP), R0
MOVD new+8(FP), R1
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index 49459b0cec..e4d02a3953 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -177,6 +177,20 @@ TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
SYSCALL
RET
+TEXT ·getpid(SB),NOSPLIT|NOFRAME,$0-8
+ MOVV $SYS_getpid, R2
+ SYSCALL
+ MOVV R2, ret+0(FP)
+ RET
+
+TEXT ·tgkill(SB),NOSPLIT|NOFRAME,$0-24
+ MOVV tgid+0(FP), R4
+ MOVV tid+8(FP), R5
+ MOVV sig+16(FP), R6
+ MOVV $SYS_tgkill, R2
+ SYSCALL
+ RET
+
TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
MOVW mode+0(FP), R4
MOVV new+8(FP), R5
diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s
index 3c405c264e..15893a7a28 100644
--- a/src/runtime/sys_linux_mipsx.s
+++ b/src/runtime/sys_linux_mipsx.s
@@ -183,6 +183,20 @@ TEXT runtime·raiseproc(SB),NOSPLIT,$0
SYSCALL
RET
+TEXT ·getpid(SB),NOSPLIT,$0-4
+ MOVW $SYS_getpid, R2
+ SYSCALL
+ MOVW R2, ret+0(FP)
+ RET
+
+TEXT ·tgkill(SB),NOSPLIT,$0-12
+ MOVW tgid+0(FP), R4
+ MOVW tid+4(FP), R5
+ MOVW sig+8(FP), R6
+ MOVW $SYS_tgkill, R2
+ SYSCALL
+ RET
+
TEXT runtime·setitimer(SB),NOSPLIT,$0-12
MOVW mode+0(FP), R4
MOVW new+4(FP), R5
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 203ce089c1..de14418338 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -156,6 +156,18 @@ TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
SYSCALL $SYS_kill
RET
+TEXT ·getpid(SB),NOSPLIT|NOFRAME,$0-8
+ SYSCALL $SYS_getpid
+ MOVD R3, ret+0(FP)
+ RET
+
+TEXT ·tgkill(SB),NOSPLIT|NOFRAME,$0-24
+ MOVD tgid+0(FP), R3
+ MOVD tid+8(FP), R4
+ MOVD sig+16(FP), R5
+ SYSCALL $SYS_tgkill
+ RET
+
TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
MOVW mode+0(FP), R3
MOVD new+8(FP), R4
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
index df01271f7b..c15a1d5364 100644
--- a/src/runtime/sys_linux_s390x.s
+++ b/src/runtime/sys_linux_s390x.s
@@ -163,6 +163,20 @@ TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
SYSCALL
RET
+TEXT ·getpid(SB),NOSPLIT|NOFRAME,$0-8
+ MOVW $SYS_getpid, R1
+ SYSCALL
+ MOVD R2, ret+0(FP)
+ RET
+
+TEXT ·tgkill(SB),NOSPLIT|NOFRAME,$0-24
+ MOVD tgid+0(FP), R2
+ MOVD tid+8(FP), R3
+ MOVD sig+16(FP), R4
+ MOVW $SYS_tgkill, R1
+ SYSCALL
+ RET
+
TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
MOVW mode+0(FP), R2
MOVD new+8(FP), R3
--
cgit v1.3-5-g9baa
From 8714e39497dba141ce7ed83c6a18c3c0def66e77 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Mon, 14 Oct 2019 17:05:56 -0400
Subject: runtime: M-targeted signals for BSDs
For these, we split up the existing runtime.raise assembly
implementation into its constituent "get thread ID" and "signal
thread" parts. This lets us implement signalM and reimplement raise in
pure Go. (NetBSD conveniently already had lwp_self.)
We also change minit to store the procid directly, rather than
depending on newosproc to do so. This is because newosproc isn't
called for the bootstrap M, but we need a procid for every M. This is
also simpler overall.
For #10958, #24543.
Change-Id: Ie5f1fcada6a33046375066bcbe054d1f784d39c0
Reviewed-on: https://go-review.googlesource.com/c/go/+/201402
Run-TryBot: Austin Clements
Reviewed-by: Cherry Zhang
---
src/runtime/defs_freebsd_386.go | 2 ++
src/runtime/defs_freebsd_amd64.go | 2 ++
src/runtime/defs_freebsd_arm.go | 2 ++
src/runtime/defs_freebsd_arm64.go | 2 ++
src/runtime/os_dragonfly.go | 25 +++++++++++++++++++------
src/runtime/os_freebsd.go | 29 ++++++++++++++++++++---------
src/runtime/os_netbsd.go | 17 ++++++++++++++++-
src/runtime/os_openbsd.go | 19 +++++++++++++------
src/runtime/sys_dragonfly_amd64.s | 12 ++++++++----
src/runtime/sys_freebsd_386.s | 15 +++++++--------
src/runtime/sys_freebsd_amd64.s | 15 +++++++++------
src/runtime/sys_freebsd_arm.s | 15 +++++++++------
src/runtime/sys_freebsd_arm64.s | 16 +++++++++++-----
src/runtime/sys_netbsd_386.s | 7 +++----
src/runtime/sys_netbsd_amd64.s | 8 +++-----
src/runtime/sys_netbsd_arm.s | 6 +++---
src/runtime/sys_netbsd_arm64.s | 7 +++----
src/runtime/sys_openbsd_386.s | 9 +++++++--
src/runtime/sys_openbsd_amd64.s | 10 +++++++---
src/runtime/sys_openbsd_arm.s | 10 +++++++---
src/runtime/sys_openbsd_arm64.s | 10 +++++++---
21 files changed, 160 insertions(+), 78 deletions(-)
(limited to 'src')
diff --git a/src/runtime/defs_freebsd_386.go b/src/runtime/defs_freebsd_386.go
index 6294fc32d4..767755425c 100644
--- a/src/runtime/defs_freebsd_386.go
+++ b/src/runtime/defs_freebsd_386.go
@@ -126,6 +126,8 @@ type thrparam struct {
spare [3]uintptr
}
+type thread int32 // long
+
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs_freebsd_amd64.go b/src/runtime/defs_freebsd_amd64.go
index 840c710eeb..5a833426fd 100644
--- a/src/runtime/defs_freebsd_amd64.go
+++ b/src/runtime/defs_freebsd_amd64.go
@@ -127,6 +127,8 @@ type thrparam struct {
spare [3]uintptr
}
+type thread int64 // long
+
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs_freebsd_arm.go b/src/runtime/defs_freebsd_arm.go
index 3307c8bbae..b55dfd88cf 100644
--- a/src/runtime/defs_freebsd_arm.go
+++ b/src/runtime/defs_freebsd_arm.go
@@ -126,6 +126,8 @@ type thrparam struct {
spare [3]uintptr
}
+type thread int32 // long
+
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs_freebsd_arm64.go b/src/runtime/defs_freebsd_arm64.go
index 3eebe5dbb3..5b9d504ba6 100644
--- a/src/runtime/defs_freebsd_arm64.go
+++ b/src/runtime/defs_freebsd_arm64.go
@@ -127,6 +127,8 @@ type thrparam struct {
spare [3]uintptr
}
+type thread int64 // long
+
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index 3266b2623a..6578fcbeb1 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -38,9 +38,11 @@ func setitimer(mode int32, new, old *itimerval)
//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-func raise(sig uint32)
func raiseproc(sig uint32)
+func lwp_gettid() int32
+func lwp_kill(pid, tid int32, sig int)
+
//go:noescape
func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
@@ -151,7 +153,7 @@ func newosproc(mp *m) {
start_func: funcPC(lwp_start),
arg: unsafe.Pointer(mp),
stack: uintptr(stk),
- tid1: unsafe.Pointer(&mp.procid),
+ tid1: nil, // minit will record tid
tid2: nil,
}
@@ -191,10 +193,7 @@ func mpreinit(mp *m) {
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
- // m.procid is a uint64, but lwp_start writes an int32. Fix it up.
- _g_ := getg()
- _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
-
+ getg().m.procid = uint64(lwp_gettid())
minitSignals()
}
@@ -288,3 +287,17 @@ func sysauxv(auxv []uintptr) {
}
}
}
+
+// raise sends a signal to the calling thread.
+//
+// It must be nosplit because it is used by the signal handler before
+// it definitely has a Go stack.
+//
+//go:nosplit
+func raise(sig uint32) {
+ lwp_kill(-1, lwp_gettid(), int(sig))
+}
+
+func signalM(mp *m, sig int) {
+ lwp_kill(-1, int32(mp.procid), sig)
+}
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index 183d8ab9c7..69e05b66a2 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -26,9 +26,11 @@ func setitimer(mode int32, new, old *itimerval)
//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-func raise(sig uint32)
func raiseproc(sig uint32)
+func thr_self() thread
+func thr_kill(tid thread, sig int)
+
//go:noescape
func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
@@ -195,7 +197,7 @@ func newosproc(mp *m) {
arg: unsafe.Pointer(mp),
stack_base: mp.g0.stack.lo,
stack_size: uintptr(stk) - mp.g0.stack.lo,
- child_tid: unsafe.Pointer(&mp.procid),
+ child_tid: nil, // minit will record tid
parent_tid: nil,
tls_base: unsafe.Pointer(&mp.tls[0]),
tls_size: unsafe.Sizeof(mp.tls),
@@ -231,7 +233,7 @@ func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
arg: nil,
stack_base: uintptr(stack), //+stacksize?
stack_size: stacksize,
- child_tid: unsafe.Pointer(&m0.procid),
+ child_tid: nil, // minit will record tid
parent_tid: nil,
tls_base: unsafe.Pointer(&m0.tls[0]),
tls_size: unsafe.Sizeof(m0.tls),
@@ -290,12 +292,7 @@ func mpreinit(mp *m) {
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
- // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
- // Fix it up. (Only matters on big-endian, but be clean anyway.)
- if sys.PtrSize == 4 {
- _g_ := getg()
- _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
- }
+ getg().m.procid = uint64(thr_self())
// On FreeBSD before about April 2017 there was a bug such
// that calling execve from a thread other than the main
@@ -423,3 +420,17 @@ func sysSigaction(sig uint32, new, old *sigactiont) {
// asmSigaction is implemented in assembly.
//go:noescape
func asmSigaction(sig uintptr, new, old *sigactiont) int32
+
+// raise sends a signal to the calling thread.
+//
+// It must be nosplit because it is used by the signal handler before
+// it definitely has a Go stack.
+//
+//go:nosplit
+func raise(sig uint32) {
+ thr_kill(thr_self(), int(sig))
+}
+
+func signalM(mp *m, sig int) {
+ thr_kill(thread(mp.procid), sig)
+}
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index 3cb9411a9c..b50cf237fb 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -47,9 +47,10 @@ func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, nds
func lwp_tramp()
-func raise(sig uint32)
func raiseproc(sig uint32)
+func lwp_kill(tid int32, sig int)
+
//go:noescape
func getcontext(ctxt unsafe.Pointer)
@@ -361,3 +362,17 @@ func sysauxv(auxv []uintptr) {
}
}
}
+
+// raise sends signal to the calling thread.
+//
+// It must be nosplit because it is used by the signal handler before
+// it definitely has a Go stack.
+//
+//go:nosplit
+func raise(sig uint32) {
+ lwp_kill(lwp_self(), int(sig))
+}
+
+func signalM(mp *m, sig int) {
+ lwp_kill(int32(mp.procid), sig)
+}
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index 351a99f7e9..f26b39575d 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -42,9 +42,11 @@ func sigprocmask(how int32, new, old *sigset) {
//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-func raise(sig uint32)
func raiseproc(sig uint32)
+func getthrid() int32
+func thrkill(tid int32, sig int)
+
//go:noescape
func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
@@ -190,7 +192,7 @@ func newosproc(mp *m) {
// rather than at the top of it.
param := tforkt{
tf_tcb: unsafe.Pointer(&mp.tls[0]),
- tf_tid: (*int32)(unsafe.Pointer(&mp.procid)),
+ tf_tid: nil, // minit will record tid
tf_stack: uintptr(stk) - sys.PtrSize,
}
@@ -238,10 +240,7 @@ func mpreinit(mp *m) {
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
func minit() {
- // m.procid is a uint64, but tfork writes an int32. Fix it up.
- _g_ := getg()
- _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
-
+ getg().m.procid = uint64(getthrid())
minitSignals()
}
@@ -337,3 +336,11 @@ func osStackRemap(s *mspan, flags int32) {
throw("remapping stack memory failed")
}
}
+
+func raise(sig uint32) {
+ thrkill(getthrid(), int(sig))
+}
+
+func signalM(mp *m, sig int) {
+ thrkill(int32(mp.procid), sig)
+}
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index 68962d9e30..580633af55 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -134,12 +134,16 @@ TEXT runtime·write1(SB),NOSPLIT,$-8
MOVL AX, ret+24(FP)
RET
-TEXT runtime·raise(SB),NOSPLIT,$16
+TEXT runtime·lwp_gettid(SB),NOSPLIT,$0-4
MOVL $496, AX // lwp_gettid
SYSCALL
- MOVQ $-1, DI // arg 1 - pid
- MOVQ AX, SI // arg 2 - tid
- MOVL sig+0(FP), DX // arg 3 - signum
+ MOVL AX, ret+0(FP)
+ RET
+
+TEXT runtime·lwp_kill(SB),NOSPLIT,$0-16
+ MOVL pid+0(FP), DI // arg 1 - pid
+ MOVL tid+4(FP), SI // arg 2 - tid
+ MOVQ sig+8(FP), DX // arg 3 - signum
MOVL $497, AX // lwp_kill
SYSCALL
RET
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index 48f64b9f8b..c346e719e1 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -131,17 +131,16 @@ TEXT runtime·write1(SB),NOSPLIT,$-4
MOVL AX, ret+12(FP)
RET
-TEXT runtime·raise(SB),NOSPLIT,$16
- // thr_self(&8(SP))
- LEAL 8(SP), AX
+TEXT runtime·thr_self(SB),NOSPLIT,$8-4
+ // thr_self(&0(FP))
+ LEAL ret+0(FP), AX
MOVL AX, 4(SP)
MOVL $432, AX
INT $0x80
- // thr_kill(self, SIGPIPE)
- MOVL 8(SP), AX
- MOVL AX, 4(SP)
- MOVL sig+0(FP), AX
- MOVL AX, 8(SP)
+ RET
+
+TEXT runtime·thr_kill(SB),NOSPLIT,$-4
+ // thr_kill(tid, sig)
MOVL $433, AX
INT $0x80
RET
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index d24ab1f643..010b2ec4d4 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -132,14 +132,17 @@ TEXT runtime·write1(SB),NOSPLIT,$-8
MOVL AX, ret+24(FP)
RET
-TEXT runtime·raise(SB),NOSPLIT,$16
- // thr_self(&8(SP))
- LEAQ 8(SP), DI // arg 1 &8(SP)
+TEXT runtime·thr_self(SB),NOSPLIT,$0-8
+ // thr_self(&0(FP))
+ LEAQ ret+0(FP), DI // arg 1
MOVL $432, AX
SYSCALL
- // thr_kill(self, SIGPIPE)
- MOVQ 8(SP), DI // arg 1 id
- MOVL sig+0(FP), SI // arg 2
+ RET
+
+TEXT runtime·thr_kill(SB),NOSPLIT,$0-16
+ // thr_kill(tid, sig)
+ MOVQ tid+0(FP), DI // arg 1 id
+ MOVQ sig+8(FP), SI // arg 2 sig
MOVL $433, AX
SYSCALL
RET
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index 8da36dff17..8dcdbb56bd 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -165,14 +165,17 @@ TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0
MOVW R0, ret+4(FP)
RET
-TEXT runtime·raise(SB),NOSPLIT,$8
- // thr_self(&4(R13))
- MOVW $4(R13), R0 // arg 1 &4(R13)
+TEXT runtime·thr_self(SB),NOSPLIT,$0-4
+ // thr_self(&0(FP))
+ MOVW $ret+0(FP), R0 // arg 1
MOVW $SYS_thr_self, R7
SWI $0
- // thr_kill(self, SIGPIPE)
- MOVW 4(R13), R0 // arg 1 id
- MOVW sig+0(FP), R1 // arg 2 - signal
+ RET
+
+TEXT runtime·thr_kill(SB),NOSPLIT,$0-8
+ // thr_kill(tid, sig)
+ MOVW tid+0(FP), R0 // arg 1 id
+ MOVW sig+4(FP), R1 // arg 2 signal
MOVW $SYS_thr_kill, R7
SWI $0
RET
diff --git a/src/runtime/sys_freebsd_arm64.s b/src/runtime/sys_freebsd_arm64.s
index ca2ea4f1d6..e0ef2f679d 100644
--- a/src/runtime/sys_freebsd_arm64.s
+++ b/src/runtime/sys_freebsd_arm64.s
@@ -197,13 +197,19 @@ TEXT runtime·usleep(SB),NOSPLIT,$24-4
SVC
RET
-// func raise(sig uint32)
-TEXT runtime·raise(SB),NOSPLIT,$8
- MOVD $8(RSP), R0 // arg 1 &8(RSP)
+// func thr_self() thread
+TEXT runtime·thr_self(SB),NOSPLIT,$8-8
+ MOVD $ptr-8(SP), R0 // arg 1 &8(SP)
MOVD $SYS_thr_self, R8
SVC
- MOVD 8(RSP), R0 // arg 1 pid
- MOVW sig+0(FP), R1
+ MOVD ptr-8(SP), R0
+ MOVD R0, ret+0(FP)
+ RET
+
+// func thr_kill(t thread, sig int)
+TEXT runtime·thr_kill(SB),NOSPLIT,$0-16
+ MOVD tid+0(FP), R0 // arg 1 pid
+ MOVD sig+8(FP), R1 // arg 2 sig
MOVD $SYS_thr_kill, R8
SVC
RET
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 7a542da526..d0c470c457 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -140,12 +140,11 @@ TEXT runtime·usleep(SB),NOSPLIT,$24
INT $0x80
RET
-TEXT runtime·raise(SB),NOSPLIT,$12
- MOVL $SYS__lwp_self, AX
- INT $0x80
+TEXT runtime·lwp_kill(SB),NOSPLIT,$12-8
MOVL $0, 0(SP)
+ MOVL tid+0(FP), AX
MOVL AX, 4(SP) // arg 1 - target
- MOVL sig+0(FP), AX
+ MOVL sig+4(FP), AX
MOVL AX, 8(SP) // arg 2 - signo
MOVL $SYS__lwp_kill, AX
INT $0x80
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index 4d1d36f01b..dc9bd127d2 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -209,11 +209,9 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
SYSCALL
RET
-TEXT runtime·raise(SB),NOSPLIT,$16
- MOVL $SYS__lwp_self, AX
- SYSCALL
- MOVQ AX, DI // arg 1 - target
- MOVL sig+0(FP), SI // arg 2 - signo
+TEXT runtime·lwp_kill(SB),NOSPLIT,$0-16
+ MOVL tid+0(FP), DI // arg 1 - target
+ MOVQ sig+8(FP), SI // arg 2 - signo
MOVL $SYS__lwp_kill, AX
SYSCALL
RET
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index c8ee262d59..64428bee4d 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -193,9 +193,9 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
SWI $SYS___nanosleep50
RET
-TEXT runtime·raise(SB),NOSPLIT,$16
- SWI $SYS__lwp_self // the returned R0 is arg 1
- MOVW sig+0(FP), R1 // arg 2 - signal
+TEXT runtime·lwp_kill(SB),NOSPLIT,$0-8
+ MOVW tid+0(FP), R0 // arg 1 - tid
+ MOVW sig+4(FP), R1 // arg 2 - signal
SWI $SYS__lwp_kill
RET
diff --git a/src/runtime/sys_netbsd_arm64.s b/src/runtime/sys_netbsd_arm64.s
index ccc34142aa..e70be0fa74 100644
--- a/src/runtime/sys_netbsd_arm64.s
+++ b/src/runtime/sys_netbsd_arm64.s
@@ -205,10 +205,9 @@ TEXT runtime·usleep(SB),NOSPLIT,$24-4
SVC $SYS___nanosleep50
RET
-TEXT runtime·raise(SB),NOSPLIT,$16
- SVC $SYS__lwp_self
- // arg 1 - target (lwp_self)
- MOVW sig+0(FP), R1 // arg 2 - signo
+TEXT runtime·lwp_kill(SB),NOSPLIT,$0-16
+ MOVW tid+0(FP), R0 // arg 1 - target
+ MOVD sig+8(FP), R1 // arg 2 - signo
SVC $SYS__lwp_kill
RET
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index 9805a43802..24fbfd6266 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -97,12 +97,17 @@ TEXT runtime·usleep(SB),NOSPLIT,$24
INT $0x80
RET
-TEXT runtime·raise(SB),NOSPLIT,$16
+TEXT runtime·getthrid(SB),NOSPLIT,$0-4
MOVL $299, AX // sys_getthrid
INT $0x80
+ MOVL AX, ret+0(FP)
+ RET
+
+TEXT runtime·thrkill(SB),NOSPLIT,$16-8
MOVL $0, 0(SP)
+ MOVL tid+0(FP), AX
MOVL AX, 4(SP) // arg 1 - tid
- MOVL sig+0(FP), AX
+ MOVL sig+4(FP), AX
MOVL AX, 8(SP) // arg 2 - signum
MOVL $0, 12(SP) // arg 3 - tcb
MOVL $119, AX // sys_thrkill
diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s
index 66526bff0d..37d70ab9aa 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -171,11 +171,15 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
SYSCALL
RET
-TEXT runtime·raise(SB),NOSPLIT,$16
+TEXT runtime·getthrid(SB),NOSPLIT,$0-4
MOVL $299, AX // sys_getthrid
SYSCALL
- MOVQ AX, DI // arg 1 - tid
- MOVL sig+0(FP), SI // arg 2 - signum
+ MOVL AX, ret+0(FP)
+ RET
+
+TEXT runtime·thrkill(SB),NOSPLIT,$0-16
+ MOVL tid+0(FP), DI // arg 1 - tid
+ MOVQ sig+8(FP), SI // arg 2 - signum
MOVQ $0, DX // arg 3 - tcb
MOVL $119, AX // sys_thrkill
SYSCALL
diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s
index 92ab3270be..2177a7308c 100644
--- a/src/runtime/sys_openbsd_arm.s
+++ b/src/runtime/sys_openbsd_arm.s
@@ -102,11 +102,15 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
SWI $0
RET
-TEXT runtime·raise(SB),NOSPLIT,$12
+TEXT runtime·getthrid(SB),NOSPLIT,$0-4
MOVW $299, R12 // sys_getthrid
SWI $0
- // arg 1 - tid, already in R0
- MOVW sig+0(FP), R1 // arg 2 - signum
+ MOVW R0, ret+0(FP)
+ RET
+
+TEXT runtime·thrkill(SB),NOSPLIT,$0-8
+ MOVW tid+0(FP), R0 // arg 1 - tid
+ MOVW sig+4(FP), R1 // arg 2 - signum
MOVW $0, R2 // arg 3 - tcb
MOVW $119, R12 // sys_thrkill
SWI $0
diff --git a/src/runtime/sys_openbsd_arm64.s b/src/runtime/sys_openbsd_arm64.s
index c8bf2d345e..8e1a5bc542 100644
--- a/src/runtime/sys_openbsd_arm64.s
+++ b/src/runtime/sys_openbsd_arm64.s
@@ -114,11 +114,15 @@ TEXT runtime·usleep(SB),NOSPLIT,$24-4
SVC
RET
-TEXT runtime·raise(SB),NOSPLIT,$0
+TEXT runtime·getthrid(SB),NOSPLIT,$0-4
MOVD $299, R8 // sys_getthrid
SVC
- // arg 1 - tid, already in R0
- MOVW sig+0(FP), R1 // arg 2 - signum
+ MOVW R0, ret+0(FP)
+ RET
+
+TEXT runtime·thrkill(SB),NOSPLIT,$0-16
+ MOVW tid+0(FP), R0 // arg 1 - tid
+ MOVD sig+8(FP), R1 // arg 2 - signum
MOVW $0, R2 // arg 3 - tcb
MOVD $119, R8 // sys_thrkill
SVC
--
cgit v1.3-5-g9baa
From 42aab4b0af5e50071fa8901a038bdc6f1f42b2ed Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Mon, 14 Oct 2019 15:49:27 -0400
Subject: runtime: M-targeted signals for libc-based OSes
For #10958, #24543.
Change-Id: I82bee63b49e15bd5a53228eb85179814c80437ef
Reviewed-on: https://go-review.googlesource.com/c/go/+/201403
Run-TryBot: Austin Clements
Reviewed-by: Cherry Zhang
---
src/runtime/os2_aix.go | 19 ++++++++++++++++++-
src/runtime/os3_solaris.go | 16 ++++++++++++++++
src/runtime/os_aix.go | 1 +
src/runtime/os_darwin.go | 5 +++++
src/runtime/sys_darwin.go | 10 ++++++++++
src/runtime/sys_darwin_386.s | 25 +++++++++++++++++++++++++
src/runtime/sys_darwin_amd64.s | 18 ++++++++++++++++++
src/runtime/sys_darwin_arm.s | 12 ++++++++++++
src/runtime/sys_darwin_arm64.s | 12 ++++++++++++
9 files changed, 117 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/runtime/os2_aix.go b/src/runtime/os2_aix.go
index 7f69d6d1e3..7c3cb27223 100644
--- a/src/runtime/os2_aix.go
+++ b/src/runtime/os2_aix.go
@@ -64,6 +64,8 @@ var (
//go:cgo_import_dynamic libpthread_attr_setstackaddr pthread_attr_setstackaddr "libpthread.a/shr_xpg5_64.o"
//go:cgo_import_dynamic libpthread_create pthread_create "libpthread.a/shr_xpg5_64.o"
//go:cgo_import_dynamic libpthread_sigthreadmask sigthreadmask "libpthread.a/shr_xpg5_64.o"
+//go:cgo_import_dynamic libpthread_self pthread_self "libpthread.a/shr_xpg5_64.o"
+//go:cgo_import_dynamic libpthread_kill pthread_kill "libpthread.a/shr_xpg5_64.o"
//go:linkname libc__Errno libc__Errno
//go:linkname libc_clock_gettime libc_clock_gettime
@@ -101,6 +103,8 @@ var (
//go:linkname libpthread_attr_setstackaddr libpthread_attr_setstackaddr
//go:linkname libpthread_create libpthread_create
//go:linkname libpthread_sigthreadmask libpthread_sigthreadmask
+//go:linkname libpthread_self libpthread_self
+//go:linkname libpthread_kill libpthread_kill
var (
//libc
@@ -139,7 +143,9 @@ var (
libpthread_attr_setdetachstate,
libpthread_attr_setstackaddr,
libpthread_create,
- libpthread_sigthreadmask libFunc
+ libpthread_sigthreadmask,
+ libpthread_self,
+ libpthread_kill libFunc
)
type libFunc uintptr
@@ -724,3 +730,14 @@ func sigprocmask(how int32, new, old *sigset) {
sigprocmask1(uintptr(how), uintptr(unsafe.Pointer(new)), uintptr(unsafe.Pointer(old)))
}
+
+//go:nosplit
+func pthread_self() pthread {
+ r, _ := syscall0(&libpthread_self)
+ return pthread(r)
+}
+
+//go:nosplit
+func signalM(mp *m, sig int) {
+ syscall2(&libpthread_kill, uintptr(pthread(mp.procid)), uintptr(sig))
+}
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 4ac191fab8..563e981d0f 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -29,6 +29,8 @@ import (
//go:cgo_import_dynamic libc_pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
//go:cgo_import_dynamic libc_pthread_attr_setstack pthread_attr_setstack "libc.so"
//go:cgo_import_dynamic libc_pthread_create pthread_create "libc.so"
+//go:cgo_import_dynamic libc_pthread_self pthread_self "libc.so"
+//go:cgo_import_dynamic libc_pthread_kill pthread_kill "libc.so"
//go:cgo_import_dynamic libc_raise raise "libc.so"
//go:cgo_import_dynamic libc_read read "libc.so"
//go:cgo_import_dynamic libc_select select "libc.so"
@@ -61,6 +63,8 @@ import (
//go:linkname libc_pthread_attr_setdetachstate libc_pthread_attr_setdetachstate
//go:linkname libc_pthread_attr_setstack libc_pthread_attr_setstack
//go:linkname libc_pthread_create libc_pthread_create
+//go:linkname libc_pthread_self libc_pthread_self
+//go:linkname libc_pthread_kill libc_pthread_kill
//go:linkname libc_raise libc_raise
//go:linkname libc_read libc_read
//go:linkname libc_select libc_select
@@ -94,6 +98,8 @@ var (
libc_pthread_attr_setdetachstate,
libc_pthread_attr_setstack,
libc_pthread_create,
+ libc_pthread_self,
+ libc_pthread_kill,
libc_raise,
libc_read,
libc_sched_yield,
@@ -214,6 +220,8 @@ func minit() {
asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
minitSignals()
+
+ getg().m.procid = uint64(pthread_self())
}
// Called from dropm to undo the effect of an minit.
@@ -434,6 +442,14 @@ func pthread_create(thread *pthread, attr *pthreadattr, fn uintptr, arg unsafe.P
return int32(sysvicall4(&libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
}
+func pthread_self() pthread {
+ return pthread(sysvicall0(&libc_pthread_self))
+}
+
+func signalM(mp *m, sig int) {
+ sysvicall2(&libc_pthread_kill, uintptr(pthread(mp.procid)), uintptr(sig))
+}
+
//go:nosplit
//go:nowritebarrierrec
func raise(sig uint32) /* int32 */ {
diff --git a/src/runtime/os_aix.go b/src/runtime/os_aix.go
index 855ae6ff46..ff2588f42f 100644
--- a/src/runtime/os_aix.go
+++ b/src/runtime/os_aix.go
@@ -175,6 +175,7 @@ func miniterrno() {
func minit() {
miniterrno()
minitSignals()
+ getg().m.procid = uint64(pthread_self())
}
func unminit() {
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index 1614b66c8a..c11fbec0a5 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -295,6 +295,7 @@ func minit() {
minitSignalStack()
}
minitSignalMask()
+ getg().m.procid = uint64(pthread_self())
}
// Called from dropm to undo the effect of an minit.
@@ -406,3 +407,7 @@ func sysargs(argc int32, argv **byte) {
executablePath = executablePath[len(prefix):]
}
}
+
+func signalM(mp *m, sig int) {
+ pthread_kill(pthread(mp.procid), uint32(sig))
+}
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index 46825d5937..31304ce737 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -162,6 +162,14 @@ func pthread_self() (t pthread) {
}
func pthread_self_trampoline()
+//go:nosplit
+//go:cgo_unsafe_args
+func pthread_kill(t pthread, sig uint32) {
+ libcCall(unsafe.Pointer(funcPC(pthread_kill_trampoline)), unsafe.Pointer(&t))
+ return
+}
+func pthread_kill_trampoline()
+
func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (unsafe.Pointer, int) {
args := struct {
addr unsafe.Pointer
@@ -415,6 +423,8 @@ func setNonblock(fd int32) {
//go:cgo_import_dynamic libc_pthread_attr_getstacksize pthread_attr_getstacksize "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_attr_setdetachstate pthread_attr_setdetachstate "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_create pthread_create "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_self pthread_self "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_kill pthread_kill "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_raise raise "/usr/lib/libSystem.B.dylib"
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index bea804b8dd..15b7cfb213 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -653,6 +653,31 @@ TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
POPL BP
RET
+TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ NOP SP // hide SP from vet
+ CALL libc_pthread_self(SB)
+ MOVL 8(SP), CX
+ MOVL AX, 0(CX) // return value
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 thread
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 sig
+ MOVL AX, 4(SP)
+ CALL libc_pthread_kill(SB)
+ MOVL BP, SP
+ POPL BP
+ RET
+
// syscall calls a function in libc on behalf of the syscall package.
// syscall takes a pointer to a struct like:
// struct {
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index ea8cf1abb1..a45ea42e5d 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -566,6 +566,24 @@ TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
POPQ BP
RET
+TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ DI, BX // BX is caller-save
+ CALL libc_pthread_self(SB)
+ MOVQ AX, 0(BX) // return value
+ POPQ BP
+ RET
+
+TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 sig
+ MOVQ 0(DI), DI // arg 1 thread
+ CALL libc_pthread_kill(SB)
+ POPQ BP
+ RET
+
// syscall calls a function in libc on behalf of the syscall package.
// syscall takes a pointer to a struct like:
// struct {
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 84b0b0f5f4..4e201fca09 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -405,6 +405,18 @@ TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
BL libc_pthread_cond_signal(SB)
RET
+TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0
+ MOVW R0, R4 // R4 is callee-save
+ BL libc_pthread_self(SB)
+ MOVW R0, 0(R4) // return value
+ RET
+
+TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 sig
+ MOVW 0(R0), R0 // arg 1 thread
+ BL libc_pthread_kill(SB)
+ RET
+
// syscall calls a function in libc on behalf of the syscall package.
// syscall takes a pointer to a struct like:
// struct {
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index 8d39a0727f..585d4f2c64 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -471,6 +471,18 @@ TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
BL libc_pthread_cond_signal(SB)
RET
+TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0
+ MOVD R0, R19 // R19 is callee-save
+ BL libc_pthread_self(SB)
+ MOVD R0, 0(R19) // return value
+ RET
+
+TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 sig
+ MOVD 0(R0), R0 // arg 1 thread
+ BL libc_pthread_kill(SB)
+ RET
+
// syscall calls a function in libc on behalf of the syscall package.
// syscall takes a pointer to a struct like:
// struct {
--
cgit v1.3-5-g9baa
From 8dc1a158e460d7fdaca3c9317405e7c0dca6e443 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Mon, 14 Oct 2019 20:10:48 -0400
Subject: runtime: add test for signalM
For #10958, #24543.
Change-Id: Ib009a83fe02bc623894f4908fe8f6b266382ba95
Reviewed-on: https://go-review.googlesource.com/c/go/+/201404
Run-TryBot: Austin Clements
Reviewed-by: Cherry Zhang
---
src/runtime/export_unix_test.go | 39 +++++++++++++++++++++++++++++++++++++++
src/runtime/preemptm_test.go | 35 +++++++++++++++++++++++++++++++++++
src/runtime/signal_unix.go | 11 ++++++++---
3 files changed, 82 insertions(+), 3 deletions(-)
create mode 100644 src/runtime/preemptm_test.go
(limited to 'src')
diff --git a/src/runtime/export_unix_test.go b/src/runtime/export_unix_test.go
index eecdfb7eb2..3f8bff619d 100644
--- a/src/runtime/export_unix_test.go
+++ b/src/runtime/export_unix_test.go
@@ -17,3 +17,42 @@ func Sigisblocked(i int) bool {
sigprocmask(_SIG_SETMASK, nil, &sigmask)
return sigismember(&sigmask, i)
}
+
+type M = m
+
+var waitForSigusr1 struct {
+ park note
+ mp *m
+}
+
+// WaitForSigusr1 blocks until a SIGUSR1 is received. It calls ready
+// when it is set up to receive SIGUSR1. The ready function should
+// cause a SIGUSR1 to be sent.
+//
+// Once SIGUSR1 is received, it returns the ID of the current M and
+// the ID of the M the SIGUSR1 was received on. If no SIGUSR1 is
+// received for timeoutNS nanoseconds, it returns -1.
+func WaitForSigusr1(ready func(mp *M), timeoutNS int64) (int64, int64) {
+ mp := getg().m
+ testSigusr1 = func(gp *g) bool {
+ waitForSigusr1.mp = gp.m
+ notewakeup(&waitForSigusr1.park)
+ return true
+ }
+ ready(mp)
+ ok := notetsleepg(&waitForSigusr1.park, timeoutNS)
+ noteclear(&waitForSigusr1.park)
+ gotM := waitForSigusr1.mp
+ waitForSigusr1.mp = nil
+ testSigusr1 = nil
+
+ if !ok {
+ return -1, -1
+ }
+ return mp.id, gotM.id
+}
+
+// SendSigusr1 sends SIGUSR1 to mp.
+func SendSigusr1(mp *M) {
+ signalM(mp, _SIGUSR1)
+}
diff --git a/src/runtime/preemptm_test.go b/src/runtime/preemptm_test.go
new file mode 100644
index 0000000000..70c6ad55cb
--- /dev/null
+++ b/src/runtime/preemptm_test.go
@@ -0,0 +1,35 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime_test
+
+import (
+ "runtime"
+ "sync"
+ "testing"
+)
+
+func TestPreemptM(t *testing.T) {
+ var want, got int64
+ var wg sync.WaitGroup
+ ready := make(chan *runtime.M)
+ wg.Add(1)
+ go func() {
+ runtime.LockOSThread()
+ want, got = runtime.WaitForSigusr1(func(mp *runtime.M) {
+ ready <- mp
+ }, 1e9)
+ runtime.UnlockOSThread()
+ wg.Done()
+ }()
+ runtime.SendSigusr1(<-ready)
+ wg.Wait()
+ if got == -1 {
+ t.Fatal("preemptM signal not received")
+ } else if want != got {
+ t.Fatalf("signal sent to M %d, but received on M %d", want, got)
+ }
+}
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index cea65282e0..27552c9f33 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -412,10 +412,11 @@ func adjustSignalStack(sig uint32, mp *m, gsigStack *gsignalStack) bool {
// GOTRACEBACK=crash when a signal is received.
var crashing int32
-// testSigtrap is used by the runtime tests. If non-nil, it is called
-// on SIGTRAP. If it returns true, the normal behavior on SIGTRAP is
-// suppressed.
+// testSigtrap and testSigusr1 are used by the runtime tests. If
+// non-nil, it is called on SIGTRAP/SIGUSR1. If it returns true, the
+// normal behavior on this signal is suppressed.
var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool
+var testSigusr1 func(gp *g) bool
// sighandler is invoked when a signal occurs. The global g will be
// set to a gsignal goroutine and we will be running on the alternate
@@ -441,6 +442,10 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
return
}
+ if sig == _SIGUSR1 && testSigusr1 != nil && testSigusr1(gp) {
+ return
+ }
+
flags := int32(_SigThrow)
if sig < uint32(len(sigtable)) {
flags = sigtable[sig].flags
--
cgit v1.3-5-g9baa
From 65a1e242094fe39c1349c7b7b19d64413b696a8c Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Tue, 25 Jun 2019 10:38:21 +0000
Subject: runtime: save/restore callee-save registers in arm's sigtramp
ARM's R4-R8 & R10-R11 are callee-save registers, and R9
may be callee-save or not. This CL saves them at the beginning
of sigtramp and restores them in the end.
fixes #32738
Change-Id: Ib7eb80836bc074e2e6a46ae4602ba8a3b96c5456
Reviewed-on: https://go-review.googlesource.com/c/go/+/183777
Reviewed-by: Cherry Zhang
---
src/runtime/sys_darwin_arm.s | 20 ++++----------------
src/runtime/sys_freebsd_arm.s | 11 ++++++++++-
src/runtime/sys_linux_arm.s | 11 ++++++++++-
src/runtime/sys_netbsd_arm.s | 11 ++++++++++-
src/runtime/sys_openbsd_arm.s | 11 ++++++++++-
5 files changed, 44 insertions(+), 20 deletions(-)
(limited to 'src')
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 4e201fca09..c08a29e7e0 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -182,14 +182,8 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
TEXT runtime·sigtramp(SB),NOSPLIT,$0
// Reserve space for callee-save registers and arguments.
- SUB $40, R13
-
- MOVW R4, 16(R13)
- MOVW R5, 20(R13)
- MOVW R6, 24(R13)
- MOVW R7, 28(R13)
- MOVW R8, 32(R13)
- MOVW R11, 36(R13)
+ MOVM.DB.W [R4-R11], (R13)
+ SUB $16, R13
// Save arguments.
MOVW R0, 4(R13) // sig
@@ -238,14 +232,8 @@ nog:
MOVW R5, R13
// Restore callee-save registers.
- MOVW 16(R13), R4
- MOVW 20(R13), R5
- MOVW 24(R13), R6
- MOVW 28(R13), R7
- MOVW 32(R13), R8
- MOVW 36(R13), R11
-
- ADD $40, R13
+ ADD $16, R13
+ MOVM.IA.W (R13), [R4-R11]
RET
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index 8dcdbb56bd..1e12f9cfcb 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -246,7 +246,11 @@ TEXT runtime·asmSigaction(SB),NOSPLIT|NOFRAME,$0
MOVW R0, ret+12(FP)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // Reserve space for callee-save registers and arguments.
+ MOVM.DB.W [R4-R11], (R13)
+ SUB $16, R13
+
// this might be called in external code context,
// where g is not set.
// first save R0, because runtime·load_g will clobber it
@@ -258,6 +262,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVW R1, 8(R13)
MOVW R2, 12(R13)
BL runtime·sigtrampgo(SB)
+
+ // Restore callee-save registers.
+ ADD $16, R13
+ MOVM.IA.W (R13), [R4-R11]
+
RET
TEXT runtime·mmap(SB),NOSPLIT,$16
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index a787440a15..9ef8c9258b 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -493,7 +493,11 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
MOVW R4, R13
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // Reserve space for callee-save registers and arguments.
+ MOVM.DB.W [R4-R11], (R13)
+ SUB $16, R13
+
// this might be called in external code context,
// where g is not set.
// first save R0, because runtime·load_g will clobber it
@@ -506,6 +510,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVW R2, 12(R13)
MOVW $runtime·sigtrampgo(SB), R11
BL (R11)
+
+ // Restore callee-save registers.
+ ADD $16, R13
+ MOVM.IA.W (R13), [R4-R11]
+
RET
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index 64428bee4d..678dea57c6 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -300,7 +300,11 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
MOVW R4, R13
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // Reserve space for callee-save registers and arguments.
+ MOVM.DB.W [R4-R11], (R13)
+ SUB $16, R13
+
// this might be called in external code context,
// where g is not set.
// first save R0, because runtime·load_g will clobber it
@@ -312,6 +316,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVW R1, 8(R13)
MOVW R2, 12(R13)
BL runtime·sigtrampgo(SB)
+
+ // Restore callee-save registers.
+ ADD $16, R13
+ MOVM.IA.W (R13), [R4-R11]
+
RET
TEXT runtime·mmap(SB),NOSPLIT,$12
diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s
index 2177a7308c..11f6e00100 100644
--- a/src/runtime/sys_openbsd_arm.s
+++ b/src/runtime/sys_openbsd_arm.s
@@ -247,7 +247,11 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
MOVW R4, R13
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // Reserve space for callee-save registers and arguments.
+ MOVM.DB.W [R4-R11], (R13)
+ SUB $16, R13
+
// If called from an external code context, g will not be set.
// Save R0, since runtime·load_g will clobber it.
MOVW R0, 4(R13) // signum
@@ -258,6 +262,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVW R1, 8(R13)
MOVW R2, 12(R13)
BL runtime·sigtrampgo(SB)
+
+ // Restore callee-save registers.
+ ADD $16, R13
+ MOVM.IA.W (R13), [R4-R11]
+
RET
// int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
--
cgit v1.3-5-g9baa
From c3e8a20a65c731eac6434a129cdaf5ed02325612 Mon Sep 17 00:00:00 2001
From: nikita-vanyasin
Date: Sat, 13 Apr 2019 16:42:48 +0300
Subject: cmd/link/internal: eliminate all ld.Cputime() usages
Also a similar 'elapsed' function and its usages were deleted.
Fixes #19865.
Change-Id: Ib125365e69cf2eda60de64fa74290c8c7d1fd65a
Reviewed-on: https://go-review.googlesource.com/c/go/+/171730
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
Reviewed-by: Than McIntosh
---
src/cmd/link/internal/amd64/asm.go | 32 +-------------------------------
src/cmd/link/internal/arm/asm.go | 27 +--------------------------
src/cmd/link/internal/arm64/asm.go | 23 -----------------------
src/cmd/link/internal/ld/data.go | 14 --------------
src/cmd/link/internal/ld/deadcode.go | 4 ----
src/cmd/link/internal/ld/dwarf.go | 4 ----
src/cmd/link/internal/ld/ld.go | 4 ++--
src/cmd/link/internal/ld/lib.go | 12 ++++++------
src/cmd/link/internal/ld/main.go | 1 -
src/cmd/link/internal/ld/pcln.go | 2 +-
src/cmd/link/internal/ld/util.go | 17 -----------------
src/cmd/link/internal/mips/asm.go | 26 --------------------------
src/cmd/link/internal/mips64/asm.go | 23 -----------------------
src/cmd/link/internal/ppc64/asm.go | 23 -----------------------
src/cmd/link/internal/s390x/asm.go | 27 ---------------------------
src/cmd/link/internal/wasm/asm.go | 4 ----
src/cmd/link/internal/x86/asm.go | 28 +---------------------------
17 files changed, 12 insertions(+), 259 deletions(-)
(limited to 'src')
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index 71e230e533..991f5523ed 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -659,14 +659,6 @@ func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
}
func asmb(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f codeblk\n", ld.Cputime())
- }
-
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -681,24 +673,14 @@ func asmb(ctxt *ld.Link) {
}
if ld.Segrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f datblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -740,9 +722,6 @@ func asmb2(ctxt *ld.Link) {
ld.Lcsize = 0
symo := int64(0)
if !*ld.FlagS {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f sym\n", ld.Cputime())
- }
switch ctxt.HeadType {
default:
case objabi.Hplan9:
@@ -775,10 +754,6 @@ func asmb2(ctxt *ld.Link) {
ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
- }
-
if ctxt.LinkMode == ld.LinkExternal {
ld.Elfemitreloc(ctxt)
}
@@ -796,9 +771,7 @@ func asmb2(ctxt *ld.Link) {
}
case objabi.Hwindows:
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
- }
+ // Do nothing
case objabi.Hdarwin:
if ctxt.LinkMode == ld.LinkExternal {
@@ -807,9 +780,6 @@ func asmb2(ctxt *ld.Link) {
}
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f headr\n", ld.Cputime())
- }
ctxt.Out.SeekSet(0)
switch ctxt.HeadType {
default:
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index d8d01f6d27..995a703dd4 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -760,10 +760,6 @@ func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
}
func asmb(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -777,24 +773,14 @@ func asmb(ctxt *ld.Link) {
}
if ld.Segrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f datblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -815,9 +801,6 @@ func asmb2(ctxt *ld.Link) {
symo := uint32(0)
if !*ld.FlagS {
// TODO: rationalize
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f sym\n", ld.Cputime())
- }
switch ctxt.HeadType {
default:
if ctxt.IsELF {
@@ -840,9 +823,6 @@ func asmb2(ctxt *ld.Link) {
switch ctxt.HeadType {
default:
if ctxt.IsELF {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
- }
ld.Asmelfsym(ctxt)
ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
@@ -864,9 +844,7 @@ func asmb2(ctxt *ld.Link) {
}
case objabi.Hwindows:
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
- }
+ // Do nothing
case objabi.Hdarwin:
if ctxt.LinkMode == ld.LinkExternal {
@@ -875,9 +853,6 @@ func asmb2(ctxt *ld.Link) {
}
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f header\n", ld.Cputime())
- }
ctxt.Out.SeekSet(0)
switch ctxt.HeadType {
default:
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index e824627bf7..9fccf73a59 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -803,10 +803,6 @@ func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
}
func asmb(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -820,24 +816,14 @@ func asmb(ctxt *ld.Link) {
}
if ld.Segrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f datblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -858,9 +844,6 @@ func asmb2(ctxt *ld.Link) {
symo := uint32(0)
if !*ld.FlagS {
// TODO: rationalize
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f sym\n", ld.Cputime())
- }
switch ctxt.HeadType {
default:
if ctxt.IsELF {
@@ -879,9 +862,6 @@ func asmb2(ctxt *ld.Link) {
switch ctxt.HeadType {
default:
if ctxt.IsELF {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
- }
ld.Asmelfsym(ctxt)
ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
@@ -909,9 +889,6 @@ func asmb2(ctxt *ld.Link) {
}
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f header\n", ld.Cputime())
- }
ctxt.Out.SeekSet(0)
switch ctxt.HeadType {
default:
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index fe167885ec..4da5ce3f70 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -559,10 +559,6 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
}
func (ctxt *Link) reloc() {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f reloc\n", Cputime())
- }
-
for _, s := range ctxt.Textp {
relocsym(ctxt, s)
}
@@ -623,9 +619,6 @@ func (ctxt *Link) windynrelocsyms() {
if !(ctxt.HeadType == objabi.Hwindows && iscgo && ctxt.LinkMode == LinkInternal) {
return
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f windynrelocsyms\n", Cputime())
- }
/* relocation table */
rel := ctxt.Syms.Lookup(".rel", 0)
@@ -672,9 +665,6 @@ func dynreloc(ctxt *Link, data *[sym.SXREF][]*sym.Symbol) {
if *FlagD {
return
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dynreloc\n", Cputime())
- }
for _, s := range ctxt.Textp {
dynrelocsym(ctxt, s)
@@ -1143,10 +1133,6 @@ func checkdatsize(ctxt *Link, datsize int64, symn sym.SymKind) {
var datap []*sym.Symbol
func (ctxt *Link) dodata() {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dodata\n", Cputime())
- }
-
if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
// The values in moduledata are filled out by relocations
// pointing to the addresses of these special symbols.
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index c880c0da01..0bc6cc457a 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -46,10 +46,6 @@ import (
//
// Any unreached text symbols are removed from ctxt.Textp.
func deadcode(ctxt *Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f deadcode\n", Cputime())
- }
-
d := &deadcodepass{
ctxt: ctxt,
ifaceMethod: make(map[methodsig]bool),
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index e426a6ba7d..e4ee58aa73 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -1798,10 +1798,6 @@ func dwarfGenerateDebugSyms(ctxt *Link) {
return
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dwarf\n", Cputime())
- }
-
abbrev := writeabbrev(ctxt)
syms := []*sym.Symbol{abbrev}
diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
index 9e5e2f9872..d277220382 100644
--- a/src/cmd/link/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -165,7 +165,7 @@ func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
pname, isshlib := findlib(ctxt, lib)
if ctxt.Debugvlog > 1 {
- ctxt.Logf("%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
+ ctxt.Logf("addlib: %s %s pulls in %s isshlib %v\n", obj, src, pname, isshlib)
}
if isshlib {
@@ -188,7 +188,7 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin
}
if ctxt.Debugvlog > 1 {
- ctxt.Logf("%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s\n", Cputime(), srcref, objref, file, pkg, shlib)
+ ctxt.Logf("addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s\n", srcref, objref, file, pkg, shlib)
}
l := &sym.Library{}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 2c5145e640..3924de530b 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -402,7 +402,7 @@ func (ctxt *Link) loadlib() {
lib := ctxt.Library[i]
if lib.Shlib == "" {
if ctxt.Debugvlog > 1 {
- ctxt.Logf("%5.2f autolib: %s (from %s)\n", Cputime(), lib.File, lib.Objref)
+ ctxt.Logf("autolib: %s (from %s)\n", lib.File, lib.Objref)
}
loadobjfile(ctxt, lib)
}
@@ -411,7 +411,7 @@ func (ctxt *Link) loadlib() {
for _, lib := range ctxt.Library {
if lib.Shlib != "" {
if ctxt.Debugvlog > 1 {
- ctxt.Logf("%5.2f autolib: %s (from %s)\n", Cputime(), lib.Shlib, lib.Objref)
+ ctxt.Logf("autolib: %s (from %s)\n", lib.Shlib, lib.Objref)
}
ldshlibsyms(ctxt, lib.Shlib)
}
@@ -842,7 +842,7 @@ func loadobjfile(ctxt *Link, lib *sym.Library) {
pkg := objabi.PathToPrefix(lib.Pkg)
if ctxt.Debugvlog > 1 {
- ctxt.Logf("%5.2f ldobj: %s (%s)\n", Cputime(), lib.File, pkg)
+ ctxt.Logf("ldobj: %s (%s)\n", lib.File, pkg)
}
f, err := bio.Open(lib.File)
if err != nil {
@@ -1439,7 +1439,7 @@ func (ctxt *Link) hostlink() {
}
if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f host link:", Cputime())
+ ctxt.Logf("host link:")
for _, v := range argv {
ctxt.Logf(" %q", v)
}
@@ -1877,7 +1877,7 @@ func ldshlibsyms(ctxt *Link, shlib string) {
}
}
if ctxt.Debugvlog > 1 {
- ctxt.Logf("%5.2f ldshlibsyms: found library with name %s at %s\n", Cputime(), shlib, libpath)
+ ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
}
f, err := elf.Open(libpath)
@@ -2387,7 +2387,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
}
if ctxt.Debugvlog != 0 || *flagN {
- ctxt.Logf("%5.2f symsize = %d\n", Cputime(), uint32(Symsize))
+ ctxt.Logf("symsize = %d\n", uint32(Symsize))
}
}
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 67e5ef9392..b62d04af2d 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -274,7 +274,6 @@ func Main(arch *sys.Arch, theArch Arch) {
ctxt.hostlink()
ctxt.archive()
if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f cpu time\n", Cputime())
ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym))
ctxt.Logf("%d liveness data\n", liveness)
}
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 9cccc7a6e9..8048695b3d 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -393,7 +393,7 @@ func (ctxt *Link) pclntab() {
ftab.Size = int64(len(ftab.P))
if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f pclntab=%d bytes, funcdata total %d bytes\n", Cputime(), ftab.Size, funcdataBytes)
+ ctxt.Logf("pclntab=%d bytes, funcdata total %d bytes\n", ftab.Size, funcdataBytes)
}
}
diff --git a/src/cmd/link/internal/ld/util.go b/src/cmd/link/internal/ld/util.go
index b5b02296a1..5ed0d72d7f 100644
--- a/src/cmd/link/internal/ld/util.go
+++ b/src/cmd/link/internal/ld/util.go
@@ -9,19 +9,8 @@ import (
"encoding/binary"
"fmt"
"os"
- "time"
)
-var startTime time.Time
-
-// TODO(josharian): delete. See issue 19865.
-func Cputime() float64 {
- if startTime.IsZero() {
- startTime = time.Now()
- }
- return time.Since(startTime).Seconds()
-}
-
var atExitFuncs []func()
func AtExit(f func()) {
@@ -84,12 +73,6 @@ func stringtouint32(x []uint32, s string) {
}
}
-var start = time.Now()
-
-func elapsed() float64 {
- return time.Since(start).Seconds()
-}
-
// contains reports whether v is in s.
func contains(s []string, v string) bool {
for _, x := range s {
diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go
index f05455e520..16c94c147a 100644
--- a/src/cmd/link/internal/mips/asm.go
+++ b/src/cmd/link/internal/mips/asm.go
@@ -163,10 +163,6 @@ func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64
}
func asmb(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -180,18 +176,10 @@ func asmb(ctxt *ld.Link) {
}
if ld.Segrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f datblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -209,33 +197,19 @@ func asmb2(ctxt *ld.Link) {
if !ctxt.IsELF {
ld.Errorf(nil, "unsupported executable format")
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f sym\n", ld.Cputime())
- }
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
ctxt.Out.SeekSet(int64(symo))
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
- }
ld.Asmelfsym(ctxt)
ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
- }
-
if ctxt.LinkMode == ld.LinkExternal {
ld.Elfemitreloc(ctxt)
}
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f header\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(0)
switch ctxt.HeadType {
default:
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index 9697ea511b..5c6fef9c5b 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -169,10 +169,6 @@ func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64
}
func asmb(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -186,24 +182,14 @@ func asmb(ctxt *ld.Link) {
}
if ld.Segrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f datblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -219,9 +205,6 @@ func asmb2(ctxt *ld.Link) {
symo := uint32(0)
if !*ld.FlagS {
// TODO: rationalize
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f sym\n", ld.Cputime())
- }
switch ctxt.HeadType {
default:
if ctxt.IsELF {
@@ -237,9 +220,6 @@ func asmb2(ctxt *ld.Link) {
switch ctxt.HeadType {
default:
if ctxt.IsELF {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
- }
ld.Asmelfsym(ctxt)
ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
@@ -262,9 +242,6 @@ func asmb2(ctxt *ld.Link) {
}
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f header\n", ld.Cputime())
- }
ctxt.Out.SeekSet(0)
switch ctxt.HeadType {
default:
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index ad91be3dad..fadff89a46 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -1062,10 +1062,6 @@ func ensureglinkresolver(ctxt *ld.Link) *sym.Symbol {
}
func asmb(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -1081,24 +1077,14 @@ func asmb(ctxt *ld.Link) {
}
if ld.Segrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f datblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -1114,9 +1100,6 @@ func asmb2(ctxt *ld.Link) {
symo := uint32(0)
if !*ld.FlagS {
// TODO: rationalize
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f sym\n", ld.Cputime())
- }
switch ctxt.HeadType {
default:
if ctxt.IsELF {
@@ -1135,9 +1118,6 @@ func asmb2(ctxt *ld.Link) {
switch ctxt.HeadType {
default:
if ctxt.IsELF {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
- }
ld.Asmelfsym(ctxt)
ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
@@ -1164,9 +1144,6 @@ func asmb2(ctxt *ld.Link) {
}
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f header\n", ld.Cputime())
- }
ctxt.Out.SeekSet(0)
switch ctxt.HeadType {
default:
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index ebaf760edf..94a5a2f86c 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -503,10 +503,6 @@ func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
}
func asmb(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -520,24 +516,14 @@ func asmb(ctxt *ld.Link) {
}
if ld.Segrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f datblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -555,32 +541,19 @@ func asmb2(ctxt *ld.Link) {
if !ctxt.IsELF {
ld.Errorf(nil, "unsupported executable format")
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f sym\n", ld.Cputime())
- }
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
ctxt.Out.SeekSet(int64(symo))
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
- }
ld.Asmelfsym(ctxt)
ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
- }
-
if ctxt.LinkMode == ld.LinkExternal {
ld.Elfemitreloc(ctxt)
}
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f header\n", ld.Cputime())
- }
ctxt.Out.SeekSet(0)
switch ctxt.HeadType {
default:
diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go
index aaaa93f355..d70b0569a6 100644
--- a/src/cmd/link/internal/wasm/asm.go
+++ b/src/cmd/link/internal/wasm/asm.go
@@ -96,10 +96,6 @@ func asmb(ctxt *ld.Link) {} // dummy
// asmb writes the final WebAssembly module binary.
// Spec: https://webassembly.github.io/spec/core/binary/modules.html
func asmb2(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
types := []*wasmFuncType{
// For normal Go functions, the single parameter is PC_B,
// the return value is
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index aa4f99e9da..3fe36db64d 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -620,10 +620,6 @@ func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
}
func asmb(ctxt *ld.Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f asmb\n", ld.Cputime())
- }
-
if ctxt.IsELF {
ld.Asmbelfsetup()
}
@@ -638,25 +634,14 @@ func asmb(ctxt *ld.Link) {
}
if ld.Segrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Segrelrodata.Filelen > 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
- }
ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f datblk\n", ld.Cputime())
- }
-
ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
@@ -676,9 +661,6 @@ func asmb2(ctxt *ld.Link) {
symo := uint32(0)
if !*ld.FlagS {
// TODO: rationalize
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f sym\n", ld.Cputime())
- }
switch ctxt.HeadType {
default:
if ctxt.IsELF {
@@ -701,9 +683,6 @@ func asmb2(ctxt *ld.Link) {
switch ctxt.HeadType {
default:
if ctxt.IsELF {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
- }
ld.Asmelfsym(ctxt)
ctxt.Out.Flush()
ctxt.Out.Write(ld.Elfstrdat)
@@ -725,9 +704,7 @@ func asmb2(ctxt *ld.Link) {
}
case objabi.Hwindows:
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
- }
+ // Do nothing
case objabi.Hdarwin:
if ctxt.LinkMode == ld.LinkExternal {
@@ -736,9 +713,6 @@ func asmb2(ctxt *ld.Link) {
}
}
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f headr\n", ld.Cputime())
- }
ctxt.Out.SeekSet(0)
switch ctxt.HeadType {
default:
--
cgit v1.3-5-g9baa
From 7e68f81dd8759ce7cc8a1ff596503f66d6a0eeae Mon Sep 17 00:00:00 2001
From: Giovanni Bajo
Date: Sat, 28 Sep 2019 00:08:45 +0200
Subject: cmd/compile: in poset, refactor aliasnode
In preparation for allowing to make multiple nodes as aliases
in a single pass, refactor aliasnode splitting out the case
in which one of the nodes is not in the post into a new
funciton (aliasnewnode).
No functional changes, passes toolstash -cmp
Change-Id: I19ca6ef8426f8aec9f2622b6151c5c617dbb25b5
Reviewed-on: https://go-review.googlesource.com/c/go/+/200859
Reviewed-by: Keith Randall
Run-TryBot: Giovanni Bajo
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/ssa/poset.go | 88 +++++++++++++++++++----------------
1 file changed, 48 insertions(+), 40 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/ssa/poset.go b/src/cmd/compile/internal/ssa/poset.go
index e3a5485d13..021771a7e7 100644
--- a/src/cmd/compile/internal/ssa/poset.go
+++ b/src/cmd/compile/internal/ssa/poset.go
@@ -407,7 +407,19 @@ func (po *poset) newconst(n *Value) {
po.upushconst(i, 0)
}
-// aliasnode records that n2 is an alias of n1
+// aliasnewnode records that a single node n2 (not in the poset yet) is an alias
+// of the master node n1.
+func (po *poset) aliasnewnode(n1, n2 *Value) {
+ i1, i2 := po.values[n1.ID], po.values[n2.ID]
+ if i1 == 0 || i2 != 0 {
+ panic("aliasnewnode invalid arguments")
+ }
+
+ po.values[n2.ID] = i1
+ po.upushalias(n2.ID, 0)
+}
+
+// aliasnode records that n2 (already in the poset) is an alias of n1
func (po *poset) aliasnode(n1, n2 *Value) {
i1 := po.values[n1.ID]
if i1 == 0 {
@@ -415,48 +427,44 @@ func (po *poset) aliasnode(n1, n2 *Value) {
}
i2 := po.values[n2.ID]
- if i2 != 0 {
- // Rename all references to i2 into i1
- // (do not touch i1 itself, otherwise we can create useless self-loops)
- for idx, n := range po.nodes {
- if uint32(idx) != i1 {
- l, r := n.l, n.r
- if l.Target() == i2 {
- po.setchl(uint32(idx), newedge(i1, l.Strict()))
- po.upush(undoSetChl, uint32(idx), l)
- }
- if r.Target() == i2 {
- po.setchr(uint32(idx), newedge(i1, r.Strict()))
- po.upush(undoSetChr, uint32(idx), r)
- }
+ if i2 == 0 {
+ panic("aliasnode for non-existing node")
+ }
+ // Rename all references to i2 into i1
+ // (do not touch i1 itself, otherwise we can create useless self-loops)
+ for idx, n := range po.nodes {
+ if uint32(idx) != i1 {
+ l, r := n.l, n.r
+ if l.Target() == i2 {
+ po.setchl(uint32(idx), newedge(i1, l.Strict()))
+ po.upush(undoSetChl, uint32(idx), l)
}
- }
-
- // Reassign all existing IDs that point to i2 to i1.
- // This includes n2.ID.
- for k, v := range po.values {
- if v == i2 {
- po.values[k] = i1
- po.upushalias(k, i2)
+ if r.Target() == i2 {
+ po.setchr(uint32(idx), newedge(i1, r.Strict()))
+ po.upush(undoSetChr, uint32(idx), r)
}
}
+ }
- if n2.isGenericIntConst() {
- val := n2.AuxInt
- if po.flags&posetFlagUnsigned != 0 {
- val = int64(n2.AuxUnsigned())
- }
- if po.constants[val] != i2 {
- panic("aliasing constant which is not registered")
- }
- po.constants[val] = i1
- po.upushconst(i1, i2)
+ // Reassign all existing IDs that point to i2 to i1.
+ // This includes n2.ID.
+ for k, v := range po.values {
+ if v == i2 {
+ po.values[k] = i1
+ po.upushalias(k, i2)
}
+ }
- } else {
- // n2.ID wasn't seen before, so record it as alias to i1
- po.values[n2.ID] = i1
- po.upushalias(n2.ID, 0)
+ if n2.isGenericIntConst() {
+ val := n2.AuxInt
+ if po.flags&posetFlagUnsigned != 0 {
+ val = int64(n2.AuxUnsigned())
+ }
+ if po.constants[val] != i2 {
+ panic("aliasing constant which is not registered")
+ }
+ po.constants[val] = i1
+ po.upushconst(i1, i2)
}
}
@@ -1093,11 +1101,11 @@ func (po *poset) SetEqual(n1, n2 *Value) bool {
i1 = po.newnode(n1)
po.roots = append(po.roots, i1)
po.upush(undoNewRoot, i1, 0)
- po.aliasnode(n1, n2)
+ po.aliasnewnode(n1, n2)
case f1 && !f2:
- po.aliasnode(n1, n2)
+ po.aliasnewnode(n1, n2)
case !f1 && f2:
- po.aliasnode(n2, n1)
+ po.aliasnewnode(n2, n1)
case f1 && f2:
if i1 == i2 {
// Already aliased, ignore
--
cgit v1.3-5-g9baa
From 18d57bc89235ea04b6db1ef3e2d4a3106f0b739e Mon Sep 17 00:00:00 2001
From: Giovanni Bajo
Date: Fri, 27 Sep 2019 23:39:42 +0200
Subject: cmd/compile: in poset, allow multiple aliases in a single pass
Change aliasnode into aliasnodes, to allow for recording
multiple aliases in a single pass. The nodes being aliased
are passed as bitset for performance reason (O(1) lookups).
It does look worse in the existing case of SetEqual where
we now need to allocate a bitset just for a single node,
but the new API will allow to fully implement a path-collapsing
primitive in next CL.
No functional changes, passes toolstash -cmp.
Change-Id: I06259610e8ef478106b36852464ed2caacd29ab5
Reviewed-on: https://go-review.googlesource.com/c/go/+/200860
Reviewed-by: Keith Randall
Run-TryBot: Giovanni Bajo
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/ssa/poset.go | 84 +++++++++++++++++++++--------------
1 file changed, 51 insertions(+), 33 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/ssa/poset.go b/src/cmd/compile/internal/ssa/poset.go
index 021771a7e7..329471ac38 100644
--- a/src/cmd/compile/internal/ssa/poset.go
+++ b/src/cmd/compile/internal/ssa/poset.go
@@ -419,52 +419,70 @@ func (po *poset) aliasnewnode(n1, n2 *Value) {
po.upushalias(n2.ID, 0)
}
-// aliasnode records that n2 (already in the poset) is an alias of n1
-func (po *poset) aliasnode(n1, n2 *Value) {
+// aliasnodes records that all the nodes i2s are aliases of a single master node n1.
+// aliasnodes takes care of rearranging the DAG, changing references of parent/children
+// of nodes in i2s, so that they point to n1 instead.
+// Complexity is O(n) (with n being the total number of nodes in the poset, not just
+// the number of nodes being aliased).
+func (po *poset) aliasnodes(n1 *Value, i2s bitset) {
i1 := po.values[n1.ID]
if i1 == 0 {
panic("aliasnode for non-existing node")
}
-
- i2 := po.values[n2.ID]
- if i2 == 0 {
- panic("aliasnode for non-existing node")
+ if i2s.Test(i1) {
+ panic("aliasnode i2s contains n1 node")
}
- // Rename all references to i2 into i1
- // (do not touch i1 itself, otherwise we can create useless self-loops)
+
+ // Go through all the nodes to adjust parent/chidlren of nodes in i2s
for idx, n := range po.nodes {
- if uint32(idx) != i1 {
- l, r := n.l, n.r
- if l.Target() == i2 {
- po.setchl(uint32(idx), newedge(i1, l.Strict()))
- po.upush(undoSetChl, uint32(idx), l)
+ // Do not touch i1 itself, otherwise we can create useless self-loops
+ if uint32(idx) == i1 {
+ continue
+ }
+ l, r := n.l, n.r
+
+ // Rename all references to i2s into i1
+ if i2s.Test(l.Target()) {
+ po.setchl(uint32(idx), newedge(i1, l.Strict()))
+ po.upush(undoSetChl, uint32(idx), l)
+ }
+ if i2s.Test(r.Target()) {
+ po.setchr(uint32(idx), newedge(i1, r.Strict()))
+ po.upush(undoSetChr, uint32(idx), r)
+ }
+
+ // Connect all chidren of i2s to i1 (unless those children
+ // are in i2s as well, in which case it would be useless)
+ if i2s.Test(uint32(idx)) {
+ if l != 0 && !i2s.Test(l.Target()) {
+ po.addchild(i1, l.Target(), l.Strict())
}
- if r.Target() == i2 {
- po.setchr(uint32(idx), newedge(i1, r.Strict()))
- po.upush(undoSetChr, uint32(idx), r)
+ if r != 0 && !i2s.Test(r.Target()) {
+ po.addchild(i1, r.Target(), r.Strict())
}
+ po.setchl(uint32(idx), 0)
+ po.setchr(uint32(idx), 0)
+ po.upush(undoSetChl, uint32(idx), l)
+ po.upush(undoSetChr, uint32(idx), r)
}
}
// Reassign all existing IDs that point to i2 to i1.
// This includes n2.ID.
for k, v := range po.values {
- if v == i2 {
+ if i2s.Test(v) {
po.values[k] = i1
- po.upushalias(k, i2)
+ po.upushalias(k, v)
}
}
- if n2.isGenericIntConst() {
- val := n2.AuxInt
- if po.flags&posetFlagUnsigned != 0 {
- val = int64(n2.AuxUnsigned())
- }
- if po.constants[val] != i2 {
- panic("aliasing constant which is not registered")
+ // If one of the aliased nodes is a constant, then make sure
+ // po.constants is updated to point to the master node.
+ for val, idx := range po.constants {
+ if i2s.Test(idx) {
+ po.constants[val] = i1
+ po.upushconst(i1, idx)
}
- po.constants[val] = i1
- po.upushconst(i1, i2)
}
}
@@ -623,7 +641,9 @@ func (po *poset) collapsepath(n1, n2 *Value) bool {
// TODO: for now, only handle the simple case of i2 being child of i1
l, r := po.children(i1)
if l.Target() == i2 || r.Target() == i2 {
- po.aliasnode(n1, n2)
+ i2s := newBitset(int(po.lastidx) + 1)
+ i2s.Set(i2)
+ po.aliasnodes(n1, i2s)
po.addchild(i1, i2, false)
return true
}
@@ -1135,11 +1155,9 @@ func (po *poset) SetEqual(n1, n2 *Value) bool {
// Set n2 as alias of n1. This will also update all the references
// to n2 to become references to n1
- po.aliasnode(n1, n2)
-
- // Connect i2 (now dummy) as child of i1. This allows to keep the correct
- // order with its children.
- po.addchild(i1, i2, false)
+ i2s := newBitset(int(po.lastidx) + 1)
+ i2s.Set(i2)
+ po.aliasnodes(n1, i2s)
}
return true
}
--
cgit v1.3-5-g9baa
From c70e5475e6ad21f4b5685ef18567a3e4e9388bbc Mon Sep 17 00:00:00 2001
From: Giovanni Bajo
Date: Sat, 28 Sep 2019 00:05:54 +0200
Subject: cmd/compile: in poset, implement path collapsing
Sometimes, poset needs to collapse a path making all nodes in
the path aliases. For instance, we know that A<=N1<=B and we
learn that B<=A, we can deduce A==N1==B, and thus we can
collapse all paths from A to B into a single aliased node.
Currently, this is a TODO. This CL implements the path-collapsing
primitive by doing a DFS walk to build a bitset of all nodes
across all paths, and then calling the new aliasnodes that allow
to mark multiple nodes as aliases of a single master node.
This helps only 4 times in std+cmd, but it will be fundamental
when we will rely on poset to calculate numerical limits, to
calculate the correct values.
This also fixes #35157, a bug uncovered by a previous CL in this
serie. A testcase will be added soon.
Change-Id: I5fc54259711769d7bd7c2d166a5abc1cddc26350
Reviewed-on: https://go-review.googlesource.com/c/go/+/200861
Run-TryBot: Giovanni Bajo
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/ssa/poset.go | 51 +++++++++---
src/cmd/compile/internal/ssa/poset_test.go | 122 ++++++++++++++++++++++++++++-
2 files changed, 161 insertions(+), 12 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/ssa/poset.go b/src/cmd/compile/internal/ssa/poset.go
index 329471ac38..f5a2b3a8c2 100644
--- a/src/cmd/compile/internal/ssa/poset.go
+++ b/src/cmd/compile/internal/ssa/poset.go
@@ -629,27 +629,56 @@ func (po *poset) mergeroot(r1, r2 uint32) uint32 {
return r
}
-// collapsepath marks i1 and i2 as equal and collapses as equal all
-// nodes across all paths between i1 and i2. If a strict edge is
+// collapsepath marks n1 and n2 as equal and collapses as equal all
+// nodes across all paths between n1 and n2. If a strict edge is
// found, the function does not modify the DAG and returns false.
+// Complexity is O(n).
func (po *poset) collapsepath(n1, n2 *Value) bool {
i1, i2 := po.values[n1.ID], po.values[n2.ID]
if po.reaches(i1, i2, true) {
return false
}
- // TODO: for now, only handle the simple case of i2 being child of i1
- l, r := po.children(i1)
- if l.Target() == i2 || r.Target() == i2 {
- i2s := newBitset(int(po.lastidx) + 1)
- i2s.Set(i2)
- po.aliasnodes(n1, i2s)
- po.addchild(i1, i2, false)
- return true
- }
+ // Find all the paths from i1 to i2
+ paths := po.findpaths(i1, i2)
+ // Mark all nodes in all the paths as aliases of n1
+ // (excluding n1 itself)
+ paths.Clear(i1)
+ po.aliasnodes(n1, paths)
return true
}
+// findpaths is a recursive function that calculates all paths from cur to dst
+// and return them as a bitset (the index of a node is set in the bitset if
+// that node is on at least one path from cur to dst).
+// We do a DFS from cur (stopping going deep any time we reach dst, if ever),
+// and mark as part of the paths any node that has a children which is already
+// part of the path (or is dst itself).
+func (po *poset) findpaths(cur, dst uint32) bitset {
+ seen := newBitset(int(po.lastidx + 1))
+ path := newBitset(int(po.lastidx + 1))
+ path.Set(dst)
+ po.findpaths1(cur, dst, seen, path)
+ return path
+}
+
+func (po *poset) findpaths1(cur, dst uint32, seen bitset, path bitset) {
+ if cur == dst {
+ return
+ }
+ seen.Set(cur)
+ l, r := po.chl(cur), po.chr(cur)
+ if !seen.Test(l) {
+ po.findpaths1(l, dst, seen, path)
+ }
+ if !seen.Test(r) {
+ po.findpaths1(r, dst, seen, path)
+ }
+ if path.Test(l) || path.Test(r) {
+ path.Set(cur)
+ }
+}
+
// Check whether it is recorded that i1!=i2
func (po *poset) isnoneq(i1, i2 uint32) bool {
if i1 == i2 {
diff --git a/src/cmd/compile/internal/ssa/poset_test.go b/src/cmd/compile/internal/ssa/poset_test.go
index 6f048a30a8..a6db1d1c24 100644
--- a/src/cmd/compile/internal/ssa/poset_test.go
+++ b/src/cmd/compile/internal/ssa/poset_test.go
@@ -438,7 +438,127 @@ func TestPosetStrict(t *testing.T) {
})
}
-func TestSetEqual(t *testing.T) {
+func TestPosetCollapse(t *testing.T) {
+ testPosetOps(t, false, []posetTestOp{
+ {Checkpoint, 0, 0},
+ // Create a complex graph of <= relations among nodes between 10 and 25.
+ {SetOrderOrEqual, 10, 15},
+ {SetOrderOrEqual, 15, 20},
+ {SetOrderOrEqual, 20, vconst(20)},
+ {SetOrderOrEqual, vconst(20), 25},
+ {SetOrderOrEqual, 10, 12},
+ {SetOrderOrEqual, 12, 16},
+ {SetOrderOrEqual, 16, vconst(20)},
+ {SetOrderOrEqual, 10, 17},
+ {SetOrderOrEqual, 17, 25},
+ {SetOrderOrEqual, 15, 18},
+ {SetOrderOrEqual, 18, vconst(20)},
+ {SetOrderOrEqual, 15, 19},
+ {SetOrderOrEqual, 19, 25},
+
+ // These are other paths not part of the main collapsing path
+ {SetOrderOrEqual, 10, 11},
+ {SetOrderOrEqual, 11, 26},
+ {SetOrderOrEqual, 13, 25},
+ {SetOrderOrEqual, 100, 25},
+ {SetOrderOrEqual, 101, 15},
+ {SetOrderOrEqual, 102, 10},
+ {SetOrderOrEqual, 25, 103},
+ {SetOrderOrEqual, 20, 104},
+
+ {Checkpoint, 0, 0},
+ // Collapse everything by setting 10 >= 25: this should make everything equal
+ {SetOrderOrEqual, 25, 10},
+
+ // Check that all nodes are pairwise equal now
+ {Equal, 10, 12},
+ {Equal, 10, 15},
+ {Equal, 10, 16},
+ {Equal, 10, 17},
+ {Equal, 10, 18},
+ {Equal, 10, 19},
+ {Equal, 10, vconst(20)},
+ {Equal, 10, vconst2(20)},
+ {Equal, 10, 25},
+
+ {Equal, 12, 15},
+ {Equal, 12, 16},
+ {Equal, 12, 17},
+ {Equal, 12, 18},
+ {Equal, 12, 19},
+ {Equal, 12, vconst(20)},
+ {Equal, 12, vconst2(20)},
+ {Equal, 12, 25},
+
+ {Equal, 15, 16},
+ {Equal, 15, 17},
+ {Equal, 15, 18},
+ {Equal, 15, 19},
+ {Equal, 15, vconst(20)},
+ {Equal, 15, vconst2(20)},
+ {Equal, 15, 25},
+
+ {Equal, 16, 17},
+ {Equal, 16, 18},
+ {Equal, 16, 19},
+ {Equal, 16, vconst(20)},
+ {Equal, 16, vconst2(20)},
+ {Equal, 16, 25},
+
+ {Equal, 17, 18},
+ {Equal, 17, 19},
+ {Equal, 17, vconst(20)},
+ {Equal, 17, vconst2(20)},
+ {Equal, 17, 25},
+
+ {Equal, 18, 19},
+ {Equal, 18, vconst(20)},
+ {Equal, 18, vconst2(20)},
+ {Equal, 18, 25},
+
+ {Equal, 19, vconst(20)},
+ {Equal, 19, vconst2(20)},
+ {Equal, 19, 25},
+
+ {Equal, vconst(20), vconst2(20)},
+ {Equal, vconst(20), 25},
+
+ {Equal, vconst2(20), 25},
+
+ // ... but not 11/26/100/101/102, which were on a different path
+ {Equal_Fail, 10, 11},
+ {Equal_Fail, 10, 26},
+ {Equal_Fail, 10, 100},
+ {Equal_Fail, 10, 101},
+ {Equal_Fail, 10, 102},
+ {OrderedOrEqual, 10, 26},
+ {OrderedOrEqual, 25, 26},
+ {OrderedOrEqual, 13, 25},
+ {OrderedOrEqual, 13, 10},
+
+ {Undo, 0, 0},
+ {OrderedOrEqual, 10, 25},
+ {Equal_Fail, 10, 12},
+ {Equal_Fail, 10, 15},
+ {Equal_Fail, 10, 25},
+
+ {Undo, 0, 0},
+ })
+
+ testPosetOps(t, false, []posetTestOp{
+ {Checkpoint, 0, 0},
+ {SetOrderOrEqual, 10, 15},
+ {SetOrderOrEqual, 15, 20},
+ {SetOrderOrEqual, 20, 25},
+ {SetOrder, 10, 16},
+ {SetOrderOrEqual, 16, 20},
+ // Check that we cannot collapse here because of the strict relation 10<16
+ {SetOrderOrEqual_Fail, 20, 10},
+ {Undo, 0, 0},
+ })
+}
+
+func TestPosetSetEqual(t *testing.T) {
testPosetOps(t, false, []posetTestOp{
// 10<=20<=30<40, 20<=100<110
{Checkpoint, 0, 0},
--
cgit v1.3-5-g9baa
From 0f559941fbd17acace0f7ce307d50c85d6941e19 Mon Sep 17 00:00:00 2001
From: Josh Bleecher Snyder
Date: Fri, 25 Oct 2019 22:36:55 -0700
Subject: crypto/tls: move a defer out of a loop
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Rhys Hiltner noted in #14939 that this defer was
syntactically inside a loop, but was only ever
executed once. Now that defer in a loop
is significantly slower, pull this one out.
name old time/op new time/op delta
Throughput/MaxPacket/1MB/TLSv12-8 3.94ms ± 8% 3.93ms ±13% ~ (p=0.967 n=15+15)
Throughput/MaxPacket/1MB/TLSv13-8 4.33ms ± 3% 4.51ms ± 7% +4.00% (p=0.000 n=14+14)
Throughput/MaxPacket/2MB/TLSv12-8 6.80ms ± 6% 7.01ms ± 4% +3.15% (p=0.000 n=14+14)
Throughput/MaxPacket/2MB/TLSv13-8 6.96ms ± 5% 6.80ms ± 5% -2.43% (p=0.006 n=15+14)
Throughput/MaxPacket/4MB/TLSv12-8 12.0ms ± 3% 11.7ms ± 2% -2.88% (p=0.000 n=15+13)
Throughput/MaxPacket/4MB/TLSv13-8 12.1ms ± 3% 11.7ms ± 2% -3.54% (p=0.000 n=13+13)
Throughput/MaxPacket/8MB/TLSv12-8 22.2ms ± 3% 21.6ms ± 3% -2.97% (p=0.000 n=15+15)
Throughput/MaxPacket/8MB/TLSv13-8 22.5ms ± 5% 22.0ms ± 3% -2.34% (p=0.004 n=15+15)
Throughput/MaxPacket/16MB/TLSv12-8 42.4ms ± 3% 41.3ms ± 3% -2.49% (p=0.001 n=15+15)
Throughput/MaxPacket/16MB/TLSv13-8 43.4ms ± 5% 42.3ms ± 3% -2.33% (p=0.006 n=15+14)
Throughput/MaxPacket/32MB/TLSv12-8 83.1ms ± 4% 80.6ms ± 3% -2.98% (p=0.000 n=15+15)
Throughput/MaxPacket/32MB/TLSv13-8 85.2ms ± 8% 82.6ms ± 4% -3.02% (p=0.005 n=15+15)
Throughput/MaxPacket/64MB/TLSv12-8 167ms ± 7% 158ms ± 2% -5.21% (p=0.000 n=15+15)
Throughput/MaxPacket/64MB/TLSv13-8 170ms ± 4% 162ms ± 3% -4.83% (p=0.000 n=15+15)
Throughput/DynamicPacket/1MB/TLSv12-8 4.13ms ± 7% 4.00ms ± 8% ~ (p=0.061 n=15+15)
Throughput/DynamicPacket/1MB/TLSv13-8 4.72ms ± 6% 4.64ms ± 7% ~ (p=0.377 n=14+15)
Throughput/DynamicPacket/2MB/TLSv12-8 7.29ms ± 7% 7.09ms ± 7% ~ (p=0.070 n=15+14)
Throughput/DynamicPacket/2MB/TLSv13-8 7.18ms ± 5% 6.59ms ± 4% -8.34% (p=0.000 n=15+15)
Throughput/DynamicPacket/4MB/TLSv12-8 12.3ms ± 3% 11.9ms ± 4% -3.31% (p=0.000 n=15+14)
Throughput/DynamicPacket/4MB/TLSv13-8 12.2ms ± 4% 12.0ms ± 4% -1.91% (p=0.019 n=15+15)
Throughput/DynamicPacket/8MB/TLSv12-8 22.4ms ± 3% 21.9ms ± 3% -2.18% (p=0.000 n=15+15)
Throughput/DynamicPacket/8MB/TLSv13-8 22.7ms ± 3% 22.2ms ± 3% -2.35% (p=0.000 n=15+15)
Throughput/DynamicPacket/16MB/TLSv12-8 42.3ms ± 3% 42.1ms ± 3% ~ (p=0.505 n=14+15)
Throughput/DynamicPacket/16MB/TLSv13-8 42.7ms ± 3% 43.3ms ± 7% ~ (p=0.123 n=15+14)
Throughput/DynamicPacket/32MB/TLSv12-8 82.8ms ± 3% 81.9ms ± 3% ~ (p=0.112 n=14+15)
Throughput/DynamicPacket/32MB/TLSv13-8 84.6ms ± 6% 83.9ms ± 4% ~ (p=0.624 n=15+15)
Throughput/DynamicPacket/64MB/TLSv12-8 166ms ± 4% 163ms ± 6% ~ (p=0.081 n=15+15)
Throughput/DynamicPacket/64MB/TLSv13-8 165ms ± 3% 168ms ± 3% +1.56% (p=0.029 n=15+15)
Change-Id: I22409b05afe761b8ed1912b15c67fc03f88d3d1f
Reviewed-on: https://go-review.googlesource.com/c/go/+/203481
Run-TryBot: Josh Bleecher Snyder
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/crypto/tls/conn.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 05048776d4..029f7443d2 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -1064,10 +1064,10 @@ func (c *Conn) Write(b []byte) (int, error) {
return 0, errClosed
}
if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
- defer atomic.AddInt32(&c.activeCall, -2)
break
}
}
+ defer atomic.AddInt32(&c.activeCall, -2)
if err := c.Handshake(); err != nil {
return 0, err
--
cgit v1.3-5-g9baa
From 0d3092ffa7e7f613429ddcfd596d26ccbc84766f Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld"
Date: Sat, 26 Oct 2019 23:05:22 +0200
Subject: internal/syscall/windows/registry: remove TestWalkFullRegistry due to
false assumptions
This test's existence was predicated upon assumptions about the full
range of known data types and known data into those types. However,
we've learned from Microsoft that there are several undocumented secret
registry types that are in use by various parts of Windows, and we've
learned from inspection that many Microsoft uses of registry types don't
strictly adhere to the recommended value size. It's therefore foolhardy
to make any assumptions about what goes in and out of the registry, and
so this test, as well as its "blacklist", are meaningless.
Fixes #35084
Change-Id: I6c3fe5fb0e740e88858321b3b042c0ff1a23284e
Reviewed-on: https://go-review.googlesource.com/c/go/+/203604
Run-TryBot: Jason A. Donenfeld
Reviewed-by: Alex Brainman
---
.../syscall/windows/registry/registry_test.go | 98 ----------------------
1 file changed, 98 deletions(-)
(limited to 'src')
diff --git a/src/internal/syscall/windows/registry/registry_test.go b/src/internal/syscall/windows/registry/registry_test.go
index 7fba960be4..8227232c70 100644
--- a/src/internal/syscall/windows/registry/registry_test.go
+++ b/src/internal/syscall/windows/registry/registry_test.go
@@ -522,104 +522,6 @@ func TestValues(t *testing.T) {
deleteValues(t, k)
}
-// These are known to be broken due to Windows bugs. See https://golang.org/issue/35084
-var blackListedKeys = map[string]bool{
- `HKCU\Software\Microsoft\Windows\CurrentVersion\Group Policy\`: true,
- `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\`: true,
- `HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Group Policy\`: true,
- `HKLM\SYSTEM\ControlSet001\`: true,
- `HKLM\SYSTEM\ControlSet002\`: true,
- `HKLM\SYSTEM\CurrentControlSet\`: true,
- `HKLM\SYSTEM\DriverDatabase\`: true,
- `HKU\`: true, // Rather unfortunate, but SIDs are hard to predict.
-}
-
-func walkKey(t *testing.T, k registry.Key, kname string) {
- if blackListedKeys[kname+`\`] {
- return
- }
- names, err := k.ReadValueNames(-1)
- if err != nil {
- t.Fatalf("reading value names of %#q failed: %v", kname+`\`, err)
- }
- for _, name := range names {
- if blackListedKeys[kname+`\`+name] {
- continue
- }
- _, valtype, err := k.GetValue(name, nil)
- if err != nil {
- t.Fatalf("reading value type of %#q in %#q failed: %v", name, kname+`\`, err)
- }
- switch valtype {
- case registry.NONE:
- case registry.SZ:
- _, _, err := k.GetStringValue(name)
- if err != nil {
- t.Errorf("getting %#q string value in %#q failed: %v", name, kname+`\`, err)
- }
- case registry.EXPAND_SZ:
- s, _, err := k.GetStringValue(name)
- if err != nil {
- t.Errorf("getting %#q expand string value in %#q failed: %v", name, kname+`\`, err)
- }
- _, err = registry.ExpandString(s)
- if err != nil {
- t.Errorf("expanding %#q value in %#q failed: %v", name, kname+`\`, err)
- }
- case registry.DWORD, registry.QWORD:
- _, _, err := k.GetIntegerValue(name)
- if err != nil {
- t.Errorf("getting %#q integer value in %#q failed: %v", name, kname+`\`, err)
- }
- case registry.BINARY:
- _, _, err := k.GetBinaryValue(name)
- if err != nil {
- t.Errorf("getting %#q binary value in %#q failed: %v", name, kname+`\`, err)
- }
- case registry.MULTI_SZ:
- _, _, err := k.GetStringsValue(name)
- if err != nil {
- t.Errorf("getting %#q strings value in %#q failed: %v", name, kname+`\`, err)
- }
- case registry.FULL_RESOURCE_DESCRIPTOR, registry.RESOURCE_LIST, registry.RESOURCE_REQUIREMENTS_LIST:
- // TODO: not implemented
- default:
- t.Fatalf("%#q in %#q has unknown value type %d", name, kname+`\`, valtype)
- }
- }
-
- names, err = k.ReadSubKeyNames(-1)
- if err != nil {
- t.Fatalf("reading sub-keys of %#q failed: %v", kname+`\`, err)
- }
- for _, name := range names {
- func() {
- subk, err := registry.OpenKey(k, name, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
- if err != nil {
- if err == syscall.ERROR_ACCESS_DENIED {
- // ignore error, if we are not allowed to access this key
- return
- }
- t.Fatalf("opening sub-keys %#q in %#q failed: %v", name, kname+`\`, err)
- }
- defer subk.Close()
-
- walkKey(t, subk, kname+`\`+name)
- }()
- }
-}
-
-func TestWalkFullRegistry(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping long running test in short mode")
- }
- walkKey(t, registry.CLASSES_ROOT, "HKCR")
- walkKey(t, registry.CURRENT_USER, "HKCU")
- walkKey(t, registry.LOCAL_MACHINE, "HKLM")
- walkKey(t, registry.USERS, "HKU")
- walkKey(t, registry.CURRENT_CONFIG, "HKCC")
-}
-
func TestExpandString(t *testing.T) {
got, err := registry.ExpandString("%PATH%")
if err != nil {
--
cgit v1.3-5-g9baa
From 31bfab4ac621e81100d7fc3bc8cf483c5d2d2fef Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld"
Date: Sat, 26 Oct 2019 22:41:31 +0200
Subject: cmd/link: enable DEP for Windows executables
There's no reason not to enable DEP in 2019, especially given Go's
minimum operating system level.
RELNOTE=yes
Change-Id: I9c3bbc5b05a1654876a218123dd57b9c9077b780
Reviewed-on: https://go-review.googlesource.com/c/go/+/203601
Reviewed-by: Alex Brainman
---
src/cmd/link/internal/ld/lib.go | 3 +++
src/cmd/link/internal/ld/pe.go | 8 ++++++--
2 files changed, 9 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 3924de530b..1edf8cf407 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1188,6 +1188,9 @@ func (ctxt *Link) hostlink() {
// ancient compatibility hacks.
argv = append(argv, "-Wl,--tsaware")
+ // Enable DEP
+ argv = append(argv, "-Wl,--nxcompat")
+
argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", PeMinimumTargetMajorVersion))
argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", PeMinimumTargetMinorVersion))
argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", PeMinimumTargetMajorVersion))
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 12363626ae..b5851a94a0 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -861,14 +861,18 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) {
switch ctxt.Arch.Family {
case sys.ARM:
- oh64.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT
- oh.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT
+ oh64.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
+ oh.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
}
// Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
+ // Enable DEP
+ oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
+ oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
+
// Disable stack growth as we don't want Windows to
// fiddle with the thread stack limits, which we set
// ourselves to circumvent the stack checks in the
--
cgit v1.3-5-g9baa
From 22d377077c01ced185f5f8d27f608e8c6dcb473c Mon Sep 17 00:00:00 2001
From: Phil Pearl
Date: Sun, 13 Oct 2019 13:01:58 +0100
Subject: encoding/json: improve performance of Compact
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This change improves performance of Compact by using a sync.Pool to allow re-use
of a scanner. This also has the side-effect of removing an allocation for each
field that implements Marshaler when marshalling JSON.
name old time/op new time/op delta
EncodeMarshaler-8 118ns ± 2% 104ns ± 1% -12.21% (p=0.001 n=7+7)
name old alloc/op new alloc/op delta
EncodeMarshaler-8 100B ± 0% 36B ± 0% -64.00% (p=0.000 n=8+8)
name old allocs/op new allocs/op delta
EncodeMarshaler-8 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=8+8)
Change-Id: Ic70c61a0a6354823da5220f5aad04b94c054f233
Reviewed-on: https://go-review.googlesource.com/c/go/+/200864
Reviewed-by: Daniel Martí
Run-TryBot: Daniel Martí
TryBot-Result: Gobot Gobot
---
src/encoding/json/bench_test.go | 19 +++++++++++++++++++
src/encoding/json/indent.go | 16 +++++++++-------
src/encoding/json/scanner.go | 36 ++++++++++++++++++++++++++++++++----
3 files changed, 60 insertions(+), 11 deletions(-)
(limited to 'src')
diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go
index f92d39f0c6..4a5fe7ec84 100644
--- a/src/encoding/json/bench_test.go
+++ b/src/encoding/json/bench_test.go
@@ -389,3 +389,22 @@ func BenchmarkTypeFieldsCache(b *testing.B) {
})
}
}
+
+func BenchmarkEncodeMarshaler(b *testing.B) {
+ b.ReportAllocs()
+
+ m := struct {
+ A int
+ B RawMessage
+ }{}
+
+ b.RunParallel(func(pb *testing.PB) {
+ enc := NewEncoder(ioutil.Discard)
+
+ for pb.Next() {
+ if err := enc.Encode(&m); err != nil {
+ b.Fatal("Encode:", err)
+ }
+ }
+ })
+}
diff --git a/src/encoding/json/indent.go b/src/encoding/json/indent.go
index 06adfc1263..2924d3b49b 100644
--- a/src/encoding/json/indent.go
+++ b/src/encoding/json/indent.go
@@ -4,7 +4,9 @@
package json
-import "bytes"
+import (
+ "bytes"
+)
// Compact appends to dst the JSON-encoded src with
// insignificant space characters elided.
@@ -14,8 +16,8 @@ func Compact(dst *bytes.Buffer, src []byte) error {
func compact(dst *bytes.Buffer, src []byte, escape bool) error {
origLen := dst.Len()
- var scan scanner
- scan.reset()
+ scan := newScanner()
+ defer freeScanner(scan)
start := 0
for i, c := range src {
if escape && (c == '<' || c == '>' || c == '&') {
@@ -36,7 +38,7 @@ func compact(dst *bytes.Buffer, src []byte, escape bool) error {
dst.WriteByte(hex[src[i+2]&0xF])
start = i + 3
}
- v := scan.step(&scan, c)
+ v := scan.step(scan, c)
if v >= scanSkipSpace {
if v == scanError {
break
@@ -78,13 +80,13 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
// if src ends in a trailing newline, so will dst.
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
origLen := dst.Len()
- var scan scanner
- scan.reset()
+ scan := newScanner()
+ defer freeScanner(scan)
needIndent := false
depth := 0
for _, c := range src {
scan.bytes++
- v := scan.step(&scan, c)
+ v := scan.step(scan, c)
if v == scanSkipSpace {
continue
}
diff --git a/src/encoding/json/scanner.go b/src/encoding/json/scanner.go
index 88572245fc..552bd70360 100644
--- a/src/encoding/json/scanner.go
+++ b/src/encoding/json/scanner.go
@@ -13,11 +13,16 @@ package json
// This file starts with two simple examples using the scanner
// before diving into the scanner itself.
-import "strconv"
+import (
+ "strconv"
+ "sync"
+)
// Valid reports whether data is a valid JSON encoding.
func Valid(data []byte) bool {
- return checkValid(data, &scanner{}) == nil
+ scan := newScanner()
+ defer freeScanner(scan)
+ return checkValid(data, scan) == nil
}
// checkValid verifies that data is valid JSON-encoded data.
@@ -45,7 +50,7 @@ type SyntaxError struct {
func (e *SyntaxError) Error() string { return e.msg }
// A scanner is a JSON scanning state machine.
-// Callers call scan.reset() and then pass bytes in one at a time
+// Callers call scan.reset and then pass bytes in one at a time
// by calling scan.step(&scan, c) for each byte.
// The return value, referred to as an opcode, tells the
// caller about significant parsing events like beginning
@@ -72,10 +77,33 @@ type scanner struct {
// Error that happened, if any.
err error
- // total bytes consumed, updated by decoder.Decode
+ // total bytes consumed, updated by decoder.Decode (and deliberately
+ // not set to zero by scan.reset)
bytes int64
}
+var scannerPool = sync.Pool{
+ New: func() interface{} {
+ return &scanner{}
+ },
+}
+
+func newScanner() *scanner {
+ scan := scannerPool.Get().(*scanner)
+ // scan.reset by design doesn't set bytes to zero
+ scan.bytes = 0
+ scan.reset()
+ return scan
+}
+
+func freeScanner(scan *scanner) {
+ // Avoid hanging on to too much memory in extreme cases.
+ if len(scan.parseState) > 1024 {
+ scan.parseState = nil
+ }
+ scannerPool.Put(scan)
+}
+
// These values are returned by the state transition functions
// assigned to scanner.state and the method scanner.eof.
// They give details about the current state of the scan that
--
cgit v1.3-5-g9baa
From 1f3339f441e2053f8efd7ead417761ea319fe790 Mon Sep 17 00:00:00 2001
From: Dan Scales
Date: Sat, 26 Oct 2019 06:53:07 -0700
Subject: runtime: fix dumpgoroutine() to deal with open-coded defers
_defer.fn can be nil, so we need to add a check when dumping
_defer.fn.fn.
Fixes #35172
Change-Id: Ic1138be5ec9dce915a87467cfa51ff83acc6e3a9
Reviewed-on: https://go-review.googlesource.com/c/go/+/203697
Run-TryBot: Dan Scales
TryBot-Result: Gobot Gobot
Reviewed-by: Austin Clements
---
src/runtime/heapdump.go | 7 ++++++-
src/runtime/runtime2.go | 8 ++++----
2 files changed, 10 insertions(+), 5 deletions(-)
(limited to 'src')
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index 992df6391e..4d55b316f7 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -371,7 +371,12 @@ func dumpgoroutine(gp *g) {
dumpint(uint64(d.sp))
dumpint(uint64(d.pc))
dumpint(uint64(uintptr(unsafe.Pointer(d.fn))))
- dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn))))
+ if d.fn == nil {
+ // d.fn can be nil for open-coded defers
+ dumpint(uint64(0))
+ } else {
+ dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn))))
+ }
dumpint(uint64(uintptr(unsafe.Pointer(d.link))))
}
for p := gp._panic; p != nil; p = p.link {
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index eecc6a78ac..c319196557 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -824,10 +824,10 @@ type _defer struct {
// defers. We have only one defer record for the entire frame (which may
// currently have 0, 1, or more defers active).
openDefer bool
- sp uintptr // sp at time of defer
- pc uintptr // pc at time of defer
- fn *funcval
- _panic *_panic // panic that is running defer
+ sp uintptr // sp at time of defer
+ pc uintptr // pc at time of defer
+ fn *funcval // can be nil for open-coded defers
+ _panic *_panic // panic that is running defer
link *_defer
// If openDefer is true, the fields below record values about the stack
--
cgit v1.3-5-g9baa
From 152dddee7ec08e0bcf9acc41487a826f468ba8ab Mon Sep 17 00:00:00 2001
From: Dmitri Goutnik
Date: Sun, 27 Oct 2019 12:22:02 -0500
Subject: cmd/link: switch to ld.bfd on freebsd/arm64
Updates golang/go#35197
Change-Id: I4fd85c84475761d71d2c17e62796e0a411cf91d8
Reviewed-on: https://go-review.googlesource.com/c/go/+/203519
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Tobias Klauser
---
src/cmd/link/internal/ld/lib.go | 13 +++++++++++++
1 file changed, 13 insertions(+)
(limited to 'src')
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 1edf8cf407..a6fa14cc74 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1294,6 +1294,19 @@ func (ctxt *Link) hostlink() {
}
}
+ if ctxt.Arch.Family == sys.ARM64 && objabi.GOOS == "freebsd" {
+ // Switch to ld.bfd on freebsd/arm64.
+ argv = append(argv, "-fuse-ld=bfd")
+
+ // Provide a useful error if ld.bfd is missing.
+ cmd := exec.Command(*flagExtld, "-fuse-ld=bfd", "-Wl,--version")
+ if out, err := cmd.CombinedOutput(); err == nil {
+ if !bytes.Contains(out, []byte("GNU ld")) {
+ log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
+ }
+ }
+ }
+
if ctxt.IsELF && len(buildinfo) > 0 {
argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
}
--
cgit v1.3-5-g9baa
From 33e3983db805ccf27f34a143d91e4346233a0ee2 Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Fri, 4 Oct 2019 10:11:29 +0200
Subject: cmd/nm, runtime/cgo: add cgo support for freebsd/arm64
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Based on work by Mikaël Urankar (@MikaelUrankar).
Updates #24715
Updates #35197
Change-Id: I91144101043d67d3f8444bf8389c9606abe2a66c
Reviewed-on: https://go-review.googlesource.com/c/go/+/199919
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/cmd/dist/build.go | 2 +-
src/cmd/nm/nm_cgo_test.go | 5 +++
src/runtime/cgo/gcc_freebsd_arm64.c | 68 +++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 1 deletion(-)
create mode 100644 src/runtime/cgo/gcc_freebsd_arm64.c
(limited to 'src')
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index bc629e1d9e..8d29eb98a7 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -1485,7 +1485,7 @@ var cgoEnabled = map[string]bool{
"freebsd/386": true,
"freebsd/amd64": true,
"freebsd/arm": true,
- "freebsd/arm64": false,
+ "freebsd/arm64": true,
"illumos/amd64": true,
"linux/386": true,
"linux/amd64": true,
diff --git a/src/cmd/nm/nm_cgo_test.go b/src/cmd/nm/nm_cgo_test.go
index 475c57b4c2..9a257e0ed2 100644
--- a/src/cmd/nm/nm_cgo_test.go
+++ b/src/cmd/nm/nm_cgo_test.go
@@ -17,6 +17,11 @@ func canInternalLink() bool {
return false
case "dragonfly":
return false
+ case "freebsd":
+ switch runtime.GOARCH {
+ case "arm64":
+ return false
+ }
case "linux":
switch runtime.GOARCH {
case "arm64", "mips64", "mips64le", "mips", "mipsle", "ppc64", "ppc64le":
diff --git a/src/runtime/cgo/gcc_freebsd_arm64.c b/src/runtime/cgo/gcc_freebsd_arm64.c
new file mode 100644
index 0000000000..dd8f888290
--- /dev/null
+++ b/src/runtime/cgo/gcc_freebsd_arm64.c
@@ -0,0 +1,68 @@
+// Copyright 2019 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.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "libcgo.h"
+#include "libcgo_unix.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+ pthread_attr_t attr;
+ size_t size;
+
+ setg_gcc = setg;
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stacklo = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ SIGFILLSET(ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+ ts->g->stackhi = size;
+ err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
--
cgit v1.3-5-g9baa
From acbed0372ea000db8b1ea69eca9d7acecdf89469 Mon Sep 17 00:00:00 2001
From: Phil Pearl
Date: Sun, 27 Oct 2019 16:05:54 +0000
Subject: encoding/json: remove allocation when using a Marshaler with value
receiver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If we marshal a non-pointer struct field whose type implements Marshaler with
a non-pointer receiver, then we avoid an allocation if we take the address of
the field before casting it to an interface.
name old time/op new time/op delta
EncodeMarshaler-8 104ns ± 1% 92ns ± 2% -11.72% (p=0.001 n=7+7)
name old alloc/op new alloc/op delta
EncodeMarshaler-8 36.0B ± 0% 4.0B ± 0% -88.89% (p=0.000 n=8+8)
name old allocs/op new allocs/op delta
EncodeMarshaler-8 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=8+8)
Test coverage already looks good enough for this change. TestRefValMarshal
already covers all possible combinations of value & pointer receivers on
value and pointer struct fields.
Change-Id: I6fc7f72396396d98f9a90c3c86e813690f41c099
Reviewed-on: https://go-review.googlesource.com/c/go/+/203608
Reviewed-by: Daniel Martí
Run-TryBot: Daniel Martí
TryBot-Result: Gobot Gobot
---
src/encoding/json/encode.go | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index a7473a7eba..b81e505866 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -399,19 +399,22 @@ var (
// newTypeEncoder constructs an encoderFunc for a type.
// The returned encoder only checks CanAddr when allowAddr is true.
func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
- if t.Implements(marshalerType) {
- return marshalerEncoder
- }
+ // If we have a non-pointer value whose type implements
+ // Marshaler with a value receiver, then we're better off taking
+ // the address of the value - otherwise we end up with an
+ // allocation as we cast the value to an interface.
if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(marshalerType) {
return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))
}
-
- if t.Implements(textMarshalerType) {
- return textMarshalerEncoder
+ if t.Implements(marshalerType) {
+ return marshalerEncoder
}
if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(textMarshalerType) {
return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false))
}
+ if t.Implements(textMarshalerType) {
+ return textMarshalerEncoder
+ }
switch t.Kind() {
case reflect.Bool:
--
cgit v1.3-5-g9baa
From adef06c7a53c16cdf8dfccbd8476417ec9b9ff9a Mon Sep 17 00:00:00 2001
From: Lynn Boger
Date: Wed, 20 Mar 2019 09:30:27 -0400
Subject: crypto/elliptic: add asm implementation for p256 on ppc64le
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This adds an asm implementation of the p256 functions used
in crypto/elliptic, utilizing VMX, VSX to improve performance.
On a power9 the improvement is:
elliptic benchmarks:
name old time/op new time/op delta
BaseMult 1.40ms ± 0% 1.44ms ± 0% +2.66% (p=0.029 n=4+4)
BaseMultP256 317µs ± 0% 50µs ± 0% -84.14% (p=0.029 n=4+4)
ScalarMultP256 854µs ± 2% 214µs ± 0% -74.91% (p=0.029 n=4+4)
ecdsa benchmarks:
name old time/op new time/op delta
SignP256 377µs ± 0% 111µs ± 0% -70.57% (p=0.029 n=4+4)
SignP384 6.55ms ± 0% 6.48ms ± 0% -1.03% (p=0.029 n=4+4)
VerifyP256 1.19ms ± 0% 0.26ms ± 0% -78.54% (p=0.029 n=4+4)
KeyGeneration 319µs ± 0% 52µs ± 0% -83.56% (p=0.029 n=4+4)
This implemenation is based on the s390x implementation, using
comparable instructions for most with some minor changes where the
instructions are not quite the same.
Some changes were also needed since s390x is big endian and ppc64le
is little endian.
This also enables the fuzz_test for ppc64le.
Change-Id: I59a69515703b82ad2929f68ba2f11208fa833181
Reviewed-on: https://go-review.googlesource.com/c/go/+/168478
Run-TryBot: Lynn Boger
TryBot-Result: Gobot Gobot
Reviewed-by: Michael Munday
---
src/crypto/elliptic/fuzz_test.go | 2 +-
src/crypto/elliptic/p256_asm_ppc64le.s | 2517 ++++++++++++++++++++++++++++++++
src/crypto/elliptic/p256_generic.go | 2 +-
src/crypto/elliptic/p256_ppc64le.go | 505 +++++++
4 files changed, 3024 insertions(+), 2 deletions(-)
create mode 100644 src/crypto/elliptic/p256_asm_ppc64le.s
create mode 100644 src/crypto/elliptic/p256_ppc64le.go
(limited to 'src')
diff --git a/src/crypto/elliptic/fuzz_test.go b/src/crypto/elliptic/fuzz_test.go
index eaeed0dacc..b9209a789b 100644
--- a/src/crypto/elliptic/fuzz_test.go
+++ b/src/crypto/elliptic/fuzz_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 arm64
+// +build amd64 arm64 ppc64le
package elliptic
diff --git a/src/crypto/elliptic/p256_asm_ppc64le.s b/src/crypto/elliptic/p256_asm_ppc64le.s
new file mode 100644
index 0000000000..4428a18260
--- /dev/null
+++ b/src/crypto/elliptic/p256_asm_ppc64le.s
@@ -0,0 +1,2517 @@
+// Copyright 2019 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.
+
+#include "textflag.h"
+
+// This is a port of the s390x asm implementation.
+// to ppc64le.
+
+// Some changes were needed due to differences in
+// the Go opcodes and/or available instructions
+// between s390x and ppc64le.
+
+// 1. There were operand order differences in the
+// VSUBUQM, VSUBCUQ, and VSEL instructions.
+
+// 2. ppc64 does not have a multiply high and low
+// like s390x, so those were implemented using
+// macros to compute the equivalent values.
+
+// 3. The LVX, STVX instructions on ppc64 require
+// 16 byte alignment of the data. To avoid that
+// requirement, data is loaded using LXVD2X and
+// STXVD2X with VPERM to reorder bytes correctly.
+
+// I have identified some areas where I believe
+// changes would be needed to make this work for big
+// endian; however additional changes beyond what I
+// have noted are most likely needed to make it work.
+// - The string used with VPERM to swap the byte order
+// for loads and stores.
+// - The EXTRACT_HI and EXTRACT_LO strings.
+// - The constants that are loaded from CPOOL.
+//
+
+// Permute string used by VPERM to reorder bytes
+// loaded or stored using LXVD2X or STXVD2X
+// on little endian.
+DATA byteswap<>+0(SB)/8, $0x08090a0b0c0d0e0f
+DATA byteswap<>+8(SB)/8, $0x0001020304050607
+
+// The following constants are defined in an order
+// that is correct for use with LXVD2X/STXVD2X
+// on little endian.
+DATA p256<>+0x00(SB)/8, $0xffffffff00000001 // P256
+DATA p256<>+0x08(SB)/8, $0x0000000000000000 // P256
+DATA p256<>+0x10(SB)/8, $0x00000000ffffffff // P256
+DATA p256<>+0x18(SB)/8, $0xffffffffffffffff // P256
+DATA p256<>+0x20(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x28(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x30(SB)/8, $0x0000000010111213 // SEL 0 d1 d0 0
+DATA p256<>+0x38(SB)/8, $0x1415161700000000 // SEL 0 d1 d0 0
+DATA p256<>+0x40(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x48(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x00(SB)/8, $0x00000000ffffffff // P256 original
+DATA p256mul<>+0x08(SB)/8, $0xffffffffffffffff // P256
+DATA p256mul<>+0x10(SB)/8, $0xffffffff00000001 // P256 original
+DATA p256mul<>+0x18(SB)/8, $0x0000000000000000 // P256
+DATA p256mul<>+0x20(SB)/8, $0x1c1d1e1f00000000 // SEL d0 0 0 d0
+DATA p256mul<>+0x28(SB)/8, $0x000000001c1d1e1f // SEL d0 0 0 d0
+DATA p256mul<>+0x30(SB)/8, $0x0001020304050607 // SEL d0 0 d1 d0
+DATA p256mul<>+0x38(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL d0 0 d1 d0
+DATA p256mul<>+0x40(SB)/8, $0x040506071c1d1e1f // SEL 0 d1 d0 d1
+DATA p256mul<>+0x48(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL 0 d1 d0 d1
+DATA p256mul<>+0x50(SB)/8, $0x0405060704050607 // SEL 0 0 d1 d0
+DATA p256mul<>+0x58(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL 0 0 d1 d0
+DATA p256mul<>+0x60(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x68(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x70(SB)/8, $0x141516170c0d0e0f // SEL 0 d1 d0 0
+DATA p256mul<>+0x78(SB)/8, $0x1c1d1e1f14151617 // SEL 0 d1 d0 0
+DATA p256mul<>+0x80(SB)/8, $0xffffffff00000000 // (1*2^256)%P256
+DATA p256mul<>+0x88(SB)/8, $0x0000000000000001 // (1*2^256)%P256
+DATA p256mul<>+0x90(SB)/8, $0x00000000fffffffe // (1*2^256)%P256
+DATA p256mul<>+0x98(SB)/8, $0xffffffffffffffff // (1*2^256)%P256
+
+// The following are used with VPERM to extract the high and low
+// values from the intermediate results of a vector multiply.
+// They are used in the VMULTxxx macros. These have been tested
+// only on little endian, I think they would have to be different
+// for big endian.
+DATA p256permhilo<>+0x00(SB)/8, $0x0405060714151617 // least significant
+DATA p256permhilo<>+0x08(SB)/8, $0x0c0d0e0f1c1d1e1f
+DATA p256permhilo<>+0x10(SB)/8, $0x0001020310111213 // most significant
+DATA p256permhilo<>+0x18(SB)/8, $0x08090a0b18191A1B
+
+// External declarations for constants
+GLOBL p256ord<>(SB), 8, $32
+GLOBL p256<>(SB), 8, $80
+GLOBL p256mul<>(SB), 8, $160
+GLOBL p256permhilo<>(SB), 8, $32
+GLOBL byteswap<>+0(SB), RODATA, $16
+
+// The following macros are used to implement the ppc64le
+// equivalent function from the corresponding s390x
+// instruction for vector multiply high, low, and add,
+// since there aren't exact equivalent instructions.
+// The corresponding s390x instructions appear in the
+// comments.
+// Implementation for big endian would have to be
+// investigated, I think it would be different.
+//
+// Vector multiply low word
+//
+// VMLF x0, x1, out_low
+#define VMULT_LOW(x1, x2, out_low) \
+ VMULUWM x1, x2, out_low
+
+ //
+ // Vector multiply high word
+ //
+ // VMLHF x0, x1, out_hi
+#define VMULT_HI(x1, x2, out_hi) \
+ VMULEUW x1, x2, TMP1; \
+ VMULOUW x1, x2, TMP2; \
+ VPERM TMP1, TMP2, EXTRACT_HI, out_hi
+
+//
+// Vector multiply word
+//
+// VMLF x0, x1, out_low
+// VMLHF x0, x1, out_hi
+#define VMULT(x1, x2, out_low, out_hi) \
+ VMULEUW x1, x2, TMP1; \
+ VMULOUW x1, x2, TMP2; \
+ VPERM TMP1, TMP2, EXTRACT_LO, out_low; \
+ VPERM TMP1, TMP2, EXTRACT_HI, out_hi
+
+//
+// Vector multiply add word
+//
+// VMALF x0, x1, y, out_low
+// VMALHF x0, x1, y, out_hi
+#define VMULT_ADD(x1, x2, y, out_low, out_hi) \
+ VSPLTISW $1, TMP1; \
+ VMULEUW y, TMP1, TMP2; \
+ VMULOUW y, TMP1, TMP1; \
+ VMULEUW x1, x2, out_low; \
+ VMULOUW x1, x2, out_hi; \
+ VADDUDM TMP1, out_hi, TMP1; \
+ VADDUDM TMP2, out_low, TMP2; \
+ VPERM TMP2, TMP1, EXTRACT_LO, out_low; \
+ VPERM TMP2, TMP1, EXTRACT_HI, out_hi
+
+//
+// Vector multiply add high word
+//
+// VMALF x0, x1, y, out_low
+// VMALHF x0, x1, y, out_hi
+#define VMULT_ADD_HI(x1, x2, y, out_low, out_hi) \
+ VSPLTISW $1, TMP1; \
+ VMULOUW y, TMP1, TMP2; \
+ VMULEUW y, TMP1, TMP1; \
+ VMULEUW x1, x2, out_hi; \
+ VMULOUW x1, x2, out_low; \
+ VADDUDM TMP1, out_hi, TMP1; \
+ VADDUDM TMP2, out_low, TMP2; \
+ VPERM TMP2, TMP1, EXTRACT_HI, out_hi
+
+//
+// Vector multiply add low word
+//
+// VMALF s0, x1, y, out_low
+#define VMULT_ADD_LOW(x1, x2, y, out_low) \
+ VMULUWM x1, x2, out_low; \
+ VADDUWM out_low, y, out_low
+
+#define res_ptr R3
+#define a_ptr R4
+
+// func p256ReverseBytes(res, in []byte)
+// Reuse of target and destination OK
+TEXT ·p256ReverseBytes(SB), NOSPLIT, $0-48
+ MOVD res+0(FP), res_ptr
+ MOVD in+24(FP), a_ptr
+
+ MOVD $8, R5
+ MOVD $16, R6
+ MOVD $24, R7
+
+ MOVDBR (R0+a_ptr), R8
+ MOVDBR (R5+a_ptr), R9
+ MOVDBR (R6+a_ptr), R10
+ MOVDBR (R7+a_ptr), R11
+
+ MOVD R11, (R0+res_ptr)
+ MOVD R10, (R5+res_ptr)
+ MOVD R9, (R6+res_ptr)
+ MOVD R8, (R7+res_ptr)
+ RET
+
+#undef res_ptr
+#undef a_ptr
+
+// func p256NegCond(val *p256Point, cond int)
+#define P1ptr R3
+#define CPOOL R7
+
+#define Y1L V0
+#define Y1L_ VS32
+#define Y1H V1
+#define Y1H_ VS33
+#define T1L V2
+#define T1L_ VS34
+#define T1H V3
+#define T1H_ VS35
+
+#define SWAP V28
+#define SWAP_ VS60
+
+#define PL V30
+#define PL_ VS62
+#define PH V31
+#define PH_ VS63
+
+#define SEL1 V5
+#define SEL1_ VS37
+#define CAR1 V6
+//
+// iff cond == 1 val <- -val
+//
+TEXT ·p256NegCond(SB), NOSPLIT, $0-16
+ MOVD val+0(FP), P1ptr
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $40, R19
+
+ MOVD cond+8(FP), R6
+ CMP $0, R6
+ BC 12, 2, LR // just return if cond == 0
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+
+ MOVD $byteswap<>+0x00(SB), R8
+ LXVD2X (R8)(R0), SWAP_
+
+ LXVD2X (P1ptr)(R17), Y1L_
+ LXVD2X (P1ptr)(R18), Y1H_
+
+ VPERM Y1H, Y1H, SWAP, Y1H
+ VPERM Y1L, Y1L, SWAP, Y1L
+
+ LXVD2X (CPOOL)(R0), PL_
+ LXVD2X (CPOOL)(R16), PH_
+
+ VSUBCUQ PL, Y1L, CAR1 // subtract part2 giving carry
+ VSUBUQM PL, Y1L, T1L // subtract part2 giving result
+ VSUBEUQM PH, Y1H, CAR1, T1H // subtract part1 using carry from part2
+
+ VPERM T1H, T1H, SWAP, T1H
+ VPERM T1L, T1L, SWAP, T1L
+
+ STXVD2X T1L_, (R17+P1ptr)
+ STXVD2X T1H_, (R18+P1ptr)
+ RET
+
+#undef P1ptr
+#undef CPOOL
+#undef Y1L
+#undef Y1L_
+#undef Y1H
+#undef Y1H_
+#undef T1L
+#undef T1L_
+#undef T1H
+#undef T1H_
+#undef PL
+#undef PL_
+#undef PH
+#undef PH_
+#undef SEL1
+#undef SEL1_
+#undef CAR1
+
+//
+// if cond == 0 res <-b else res <-a
+//
+// func p256MovCond(res, a, b *p256Point, cond int)
+#define P3ptr R3
+#define P1ptr R4
+#define P2ptr R5
+
+#define FROMptr R7
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X1L_ VS32
+#define X1H_ VS33
+#define Y1L_ VS34
+#define Y1H_ VS35
+#define Z1L_ VS36
+#define Z1H_ VS37
+
+// This function uses LXVD2X and STXVD2X to avoid the
+// data alignment requirement for LVX, STVX. Since
+// this code is just moving bytes and not doing arithmetic,
+// order of the bytes doesn't matter.
+//
+TEXT ·p256MovCond(SB), NOSPLIT, $0-32
+ MOVD res+0(FP), P3ptr
+ MOVD a+8(FP), P1ptr
+ MOVD b+16(FP), P2ptr
+ MOVD cond+24(FP), R6
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $56, R21
+ MOVD $64, R19
+ MOVD $80, R20
+
+ // Check the condition
+ CMP $0, R6
+
+ // If 0, use b as the source
+ BEQ FROMB
+
+ // Not 0, use a as the source
+ MOVD P1ptr, FROMptr
+ BR LOADVALS
+
+FROMB:
+ MOVD P2ptr, FROMptr
+
+LOADVALS:
+ // Load from a or b depending on the setting
+ // of FROMptr
+ LXVW4X (FROMptr+R0), X1H_
+ LXVW4X (FROMptr+R16), X1L_
+ LXVW4X (FROMptr+R17), Y1H_
+ LXVW4X (FROMptr+R18), Y1L_
+ LXVW4X (FROMptr+R19), Z1H_
+ LXVW4X (FROMptr+R20), Z1L_
+
+ STXVW4X X1H_, (P3ptr+R0)
+ STXVW4X X1L_, (P3ptr+R16)
+ STXVW4X Y1H_, (P3ptr+R17)
+ STXVW4X Y1L_, (P3ptr+R18)
+ STXVW4X Z1H_, (P3ptr+R19)
+ STXVW4X Z1L_, (P3ptr+R20)
+
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef P2ptr
+#undef FROMptr
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X1L_
+#undef X1H_
+#undef Y1L_
+#undef Y1H_
+#undef Z1L_
+#undef Z1H_
+//
+// Select the point from the table for idx
+//
+// func p256Select(point *p256Point, table []p256Point, idx int)
+#define P3ptr R3
+#define P1ptr R4
+#define COUNT R5
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X1L_ VS32
+#define X1H_ VS33
+#define Y1L_ VS34
+#define Y1H_ VS35
+#define Z1L_ VS36
+#define Z1H_ VS37
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+#define X2L_ VS38
+#define X2H_ VS39
+#define Y2L_ VS40
+#define Y2H_ VS41
+#define Z2L_ VS42
+#define Z2H_ VS43
+
+#define ONE V18
+#define IDX V19
+#define SEL1 V20
+#define SEL1_ VS52
+#define SEL2 V21
+//
+TEXT ·p256Select(SB), NOSPLIT, $0-40
+ MOVD point+0(FP), P3ptr
+ MOVD table+8(FP), P1ptr
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+
+ LXVDSX (R1)(R19), SEL1_ // VLREPG idx+32(FP), SEL1
+ VSPLTB $7, SEL1, IDX // splat byte
+ VSPLTISB $1, ONE // VREPIB $1, ONE
+ VSPLTISB $1, SEL2 // VREPIB $1, SEL2
+ MOVD $17, COUNT
+ MOVD COUNT, CTR // set up ctr
+
+ VSPLTISB $0, X1H // VZERO X1H
+ VSPLTISB $0, X1L // VZERO X1L
+ VSPLTISB $0, Y1H // VZERO Y1H
+ VSPLTISB $0, Y1L // VZERO Y1L
+ VSPLTISB $0, Z1H // VZERO Z1H
+ VSPLTISB $0, Z1L // VZERO Z1L
+
+loop_select:
+
+ // LVXD2X is used here since data alignment doesn't
+ // matter.
+
+ LXVD2X (P1ptr+R0), X2H_
+ LXVD2X (P1ptr+R16), X2L_
+ LXVD2X (P1ptr+R17), Y2H_
+ LXVD2X (P1ptr+R18), Y2L_
+ LXVD2X (P1ptr+R19), Z2H_
+ LXVD2X (P1ptr+R20), Z2L_
+
+ VCMPEQUD SEL2, IDX, SEL1 // VCEQG SEL2, IDX, SEL1 OK
+
+ // This will result in SEL1 being all 0s or 1s, meaning
+ // the result is either X1L or X2L, no individual byte
+ // selection.
+
+ VSEL X1L, X2L, SEL1, X1L
+ VSEL X1H, X2H, SEL1, X1H
+ VSEL Y1L, Y2L, SEL1, Y1L
+ VSEL Y1H, Y2H, SEL1, Y1H
+ VSEL Z1L, Z2L, SEL1, Z1L
+ VSEL Z1H, Z2H, SEL1, Z1H
+
+ // Add 1 to all bytes in SEL2
+ VADDUBM SEL2, ONE, SEL2 // VAB SEL2, ONE, SEL2 OK
+ ADD $96, P1ptr
+ BC 16, 0, loop_select
+
+ // STXVD2X is used here so that alignment doesn't
+ // need to be verified. Since values were loaded
+ // using LXVD2X this is OK.
+ STXVD2X X1H_, (P3ptr+R0)
+ STXVD2X X1L_, (P3ptr+R16)
+ STXVD2X Y1H_, (P3ptr+R17)
+ STXVD2X Y1L_, (P3ptr+R18)
+ STXVD2X Z1H_, (P3ptr+R19)
+ STXVD2X Z1L_, (P3ptr+R20)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef COUNT
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef X2L_
+#undef X2H_
+#undef Y2L_
+#undef Y2H_
+#undef Z2L_
+#undef Z2H_
+#undef ONE
+#undef IDX
+#undef SEL1
+#undef SEL1_
+#undef SEL2
+
+// func p256SelectBase(point, table []uint64, idx int)
+#define P3ptr R3
+#define P1ptr R4
+#define COUNT R5
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+#define X2L_ VS38
+#define X2H_ VS39
+#define Y2L_ VS40
+#define Y2H_ VS41
+#define Z2L_ VS42
+#define Z2H_ VS43
+
+#define ONE V18
+#define IDX V19
+#define SEL1 V20
+#define SEL1_ VS52
+#define SEL2 V21
+TEXT ·p256SelectBase(SB), NOSPLIT, $0-40
+ MOVD point+0(FP), P3ptr
+ MOVD table+8(FP), P1ptr
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+ MOVD $56, R21
+
+ LXVDSX (R1)(R19), SEL1_
+ VSPLTB $7, SEL1, IDX // splat byte
+
+ VSPLTISB $1, ONE // Vector with byte 1s
+ VSPLTISB $1, SEL2 // Vector with byte 1s
+ MOVD $65, COUNT
+ MOVD COUNT, CTR // loop count
+
+ VSPLTISB $0, X1H // VZERO X1H
+ VSPLTISB $0, X1L // VZERO X1L
+ VSPLTISB $0, Y1H // VZERO Y1H
+ VSPLTISB $0, Y1L // VZERO Y1L
+ VSPLTISB $0, Z1H // VZERO Z1H
+ VSPLTISB $0, Z1L // VZERO Z1L
+
+loop_select:
+ LXVD2X (P1ptr+R0), X2H_
+ LXVD2X (P1ptr+R16), X2L_
+ LXVD2X (P1ptr+R17), Y2H_
+ LXVD2X (P1ptr+R18), Y2L_
+ LXVD2X (P1ptr+R19), Z2H_
+ LXVD2X (P1ptr+R20), Z2L_
+
+ VCMPEQUD SEL2, IDX, SEL1 // Compare against idx
+
+ VSEL X1L, X2L, SEL1, X1L // Select if idx matched
+ VSEL X1H, X2H, SEL1, X1H
+ VSEL Y1L, Y2L, SEL1, Y1L
+ VSEL Y1H, Y2H, SEL1, Y1H
+ VSEL Z1L, Z2L, SEL1, Z1L
+ VSEL Z1H, Z2H, SEL1, Z1H
+
+ VADDUBM SEL2, ONE, SEL2 // Increment SEL2 bytes by 1
+ ADD $96, P1ptr // Next chunk
+ BC 16, 0, loop_select
+
+ STXVD2X X1H_, (P3ptr+R0)
+ STXVD2X X1L_, (P3ptr+R16)
+ STXVD2X Y1H_, (P3ptr+R17)
+ STXVD2X Y1L_, (P3ptr+R18)
+ STXVD2X Z1H_, (P3ptr+R19)
+ STXVD2X Z1L_, (P3ptr+R20)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef COUNT
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef X1L_
+#undef X1H_
+#undef X2L_
+#undef X2H_
+#undef Y1L_
+#undef Y1H_
+#undef Y2L_
+#undef Y2H_
+#undef Z1L_
+#undef Z1H_
+#undef Z2L_
+#undef Z2H_
+#undef ONE
+#undef IDX
+#undef SEL1
+#undef SEL1_
+#undef SEL2
+#undef SWAP
+#undef SWAP_
+
+// ---------------------------------------
+// func p256FromMont(res, in []byte)
+#define res_ptr R3
+#define x_ptr R4
+#define CPOOL R7
+
+#define T0 V0
+#define T0_ VS32
+#define T1 V1
+#define T1_ VS33
+#define T2 V2
+#define TT0 V3
+#define TT1 V4
+#define TT0_ VS35
+#define TT1_ VS36
+
+#define ZER V6
+#define SEL1 V7
+#define SEL1_ VS39
+#define SEL2 V8
+#define SEL2_ VS40
+#define CAR1 V9
+#define CAR2 V10
+#define RED1 V11
+#define RED2 V12
+#define PL V13
+#define PL_ VS45
+#define PH V14
+#define PH_ VS46
+#define SWAP V28
+#define SWAP_ VS57
+
+TEXT ·p256FromMont(SB), NOSPLIT, $0-48
+ MOVD res+0(FP), res_ptr
+ MOVD in+24(FP), x_ptr
+
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $p256<>+0x00(SB), CPOOL
+ MOVD $byteswap<>+0x00(SB), R15
+
+ VSPLTISB $0, T2 // VZERO T2
+ VSPLTISB $0, ZER // VZERO ZER
+
+ // Constants are defined so that the LXVD2X is correct
+ LXVD2X (CPOOL+R0), PH_
+ LXVD2X (CPOOL+R16), PL_
+
+ // VPERM byte selections
+ LXVD2X (CPOOL+R18), SEL2_
+ LXVD2X (CPOOL+R19), SEL1_
+
+ LXVD2X (R15)(R0), SWAP_
+
+ LXVD2X (R16)(x_ptr), T1_
+ LXVD2X (R0)(x_ptr), T0_
+
+ // Put in true little endian order
+ VPERM T0, T0, SWAP, T0
+ VPERM T1, T1, SWAP, T1
+
+ // First round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSUBUQM RED2, RED1, RED2 // VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
+ VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ T0, RED1, CAR1
+ VADDUQM T0, RED1, T0 // VAQ T0, RED1, T0
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ T1, RED2, CAR1, T1
+ VADDUQM T2, CAR2, T2 // VAQ T2, CAR2, T2
+
+ // Second round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSUBUQM RED2, RED1, RED2 // VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
+ VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ T0, RED1, CAR1
+ VADDUQM T0, RED1, T0 // VAQ T0, RED1, T0
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ T1, RED2, CAR1, T1
+ VADDUQM T2, CAR2, T2 // VAQ T2, CAR2, T2
+
+ // Third round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSUBUQM RED2, RED1, RED2 // VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
+ VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ T0, RED1, CAR1
+ VADDUQM T0, RED1, T0 // VAQ T0, RED1, T0
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ T1, RED2, CAR1, T1
+ VADDUQM T2, CAR2, T2 // VAQ T2, CAR2, T2
+
+ // Last round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSUBUQM RED2, RED1, RED2 // VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
+ VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ T0, RED1, CAR1
+ VADDUQM T0, RED1, T0 // VAQ T0, RED1, T0
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ T1, RED2, CAR1, T1
+ VADDUQM T2, CAR2, T2 // VAQ T2, CAR2, T2
+
+ // ---------------------------------------------------
+
+ VSUBCUQ T0, PL, CAR1 // VSCBIQ PL, T0, CAR1
+ VSUBUQM T0, PL, TT0 // VSQ PL, T0, TT0
+ VSUBECUQ T1, PH, CAR1, CAR2 // VSBCBIQ T1, PH, CAR1, CAR2
+ VSUBEUQM T1, PH, CAR1, TT1 // VSBIQ T1, PH, CAR1, TT1
+ VSUBEUQM T2, ZER, CAR2, T2 // VSBIQ T2, ZER, CAR2, T2
+
+ VSEL TT0, T0, T2, T0
+ VSEL TT1, T1, T2, T1
+
+ // Reorder the bytes so STXVD2X can be used.
+ // TT0, TT1 used for VPERM result in case
+ // the caller expects T0, T1 to be good.
+ VPERM T0, T0, SWAP, TT0
+ VPERM T1, T1, SWAP, TT1
+
+ STXVD2X TT0_, (R0)(res_ptr)
+ STXVD2X TT1_, (R16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef CPOOL
+#undef T0
+#undef T0_
+#undef T1
+#undef T1_
+#undef T2
+#undef TT0
+#undef TT1
+#undef ZER
+#undef SEL1
+#undef SEL1_
+#undef SEL2
+#undef SEL2_
+#undef CAR1
+#undef CAR2
+#undef RED1
+#undef RED2
+#undef PL
+#undef PL_
+#undef PH
+#undef PH_
+#undef SWAP
+#undef SWAP_
+
+// ---------------------------------------
+// p256MulInternal
+// V0-V3 V30,V31 - Not Modified
+// V4-V15 V27-V29 - Volatile
+
+#define CPOOL R7
+
+// Parameters
+#define X0 V0 // Not modified
+#define X1 V1 // Not modified
+#define Y0 V2 // Not modified
+#define Y1 V3 // Not modified
+#define T0 V4 // Result
+#define T1 V5 // Result
+#define P0 V30 // Not modified
+#define P1 V31 // Not modified
+
+// Temporaries: lots of reused vector regs
+#define YDIG V6 // Overloaded with CAR2
+#define ADD1H V7 // Overloaded with ADD3H
+#define ADD2H V8 // Overloaded with ADD4H
+#define ADD3 V9 // Overloaded with SEL2,SEL5
+#define ADD4 V10 // Overloaded with SEL3,SEL6
+#define RED1 V11 // Overloaded with CAR2
+#define RED2 V12
+#define RED3 V13 // Overloaded with SEL1
+#define T2 V14
+// Overloaded temporaries
+#define ADD1 V4 // Overloaded with T0
+#define ADD2 V5 // Overloaded with T1
+#define ADD3H V7 // Overloaded with ADD1H
+#define ADD4H V8 // Overloaded with ADD2H
+#define ZER V28 // Overloaded with TMP1
+#define CAR1 V6 // Overloaded with YDIG
+#define CAR2 V11 // Overloaded with RED1
+// Constant Selects
+#define SEL1 V13 // Overloaded with RED3
+#define SEL2 V9 // Overloaded with ADD3,SEL5
+#define SEL3 V10 // Overloaded with ADD4,SEL6
+#define SEL4 V6 // Overloaded with YDIG,CAR1
+#define SEL5 V9 // Overloaded with ADD3,SEL2
+#define SEL6 V10 // Overloaded with ADD4,SEL3
+#define SEL1_ VS45
+#define SEL2_ VS41
+#define SEL3_ VS42
+#define SEL4_ VS38
+#define SEL5_ VS41
+#define SEL6_ VS42
+
+// TMP1, TMP2, EXTRACT_LO, EXTRACT_HI used in
+// VMULT macros
+#define TMP1 V13 // Overloaded with RED3
+#define TMP2 V27
+#define EVENODD R5
+#define EXTRACT_LO V28
+#define EXTRACT_LO_ VS60
+#define EXTRACT_HI V29
+#define EXTRACT_HI_ VS61
+
+/* *
+ * To follow the flow of bits, for your own sanity a stiff drink, need you shall.
+ * Of a single round, a 'helpful' picture, here is. Meaning, column position has.
+ * With you, SIMD be...
+ *
+ * +--------+--------+
+ * +--------| RED2 | RED1 |
+ * | +--------+--------+
+ * | ---+--------+--------+
+ * | +---- T2| T1 | T0 |--+
+ * | | ---+--------+--------+ |
+ * | | |
+ * | | ======================= |
+ * | | |
+ * | | +--------+--------+<-+
+ * | +-------| ADD2 | ADD1 |--|-----+
+ * | | +--------+--------+ | |
+ * | | +--------+--------+<---+ |
+ * | | | ADD2H | ADD1H |--+ |
+ * | | +--------+--------+ | |
+ * | | +--------+--------+<-+ |
+ * | | | ADD4 | ADD3 |--|-+ |
+ * | | +--------+--------+ | | |
+ * | | +--------+--------+<---+ | |
+ * | | | ADD4H | ADD3H |------|-+ |(+vzero)
+ * | | +--------+--------+ | | V
+ * | | ------------------------ | | +--------+
+ * | | | | | RED3 | [d0 0 0 d0]
+ * | | | | +--------+
+ * | +---->+--------+--------+ | | |
+ * (T2[1w]||ADD2[4w]||ADD1[3w]) +--------| T1 | T0 | | | |
+ * | +--------+--------+ | | |
+ * +---->---+--------+--------+ | | |
+ * T2| T1 | T0 |----+ | |
+ * ---+--------+--------+ | | |
+ * ---+--------+--------+<---+ | |
+ * +--- T2| T1 | T0 |----------+
+ * | ---+--------+--------+ | |
+ * | +--------+--------+<-------------+
+ * | | RED2 | RED1 |-----+ | | [0 d1 d0 d1] [d0 0 d1 d0]
+ * | +--------+--------+ | | |
+ * | +--------+<----------------------+
+ * | | RED3 |--------------+ | [0 0 d1 d0]
+ * | +--------+ | |
+ * +--->+--------+--------+ | |
+ * | T1 | T0 |--------+
+ * +--------+--------+ | |
+ * --------------------------- | |
+ * | |
+ * +--------+--------+<----+ |
+ * | RED2 | RED1 | |
+ * +--------+--------+ |
+ * ---+--------+--------+<-------+
+ * T2| T1 | T0 | (H1P-H1P-H00RRAY!)
+ * ---+--------+--------+
+ *
+ * *Mi obra de arte de siglo XXI @vpaprots
+ *
+ *
+ * First group is special, doesnt get the two inputs:
+ * +--------+--------+<-+
+ * +-------| ADD2 | ADD1 |--|-----+
+ * | +--------+--------+ | |
+ * | +--------+--------+<---+ |
+ * | | ADD2H | ADD1H |--+ |
+ * | +--------+--------+ | |
+ * | +--------+--------+<-+ |
+ * | | ADD4 | ADD3 |--|-+ |
+ * | +--------+--------+ | | |
+ * | +--------+--------+<---+ | |
+ * | | ADD4H | ADD3H |------|-+ |(+vzero)
+ * | +--------+--------+ | | V
+ * | ------------------------ | | +--------+
+ * | | | | RED3 | [d0 0 0 d0]
+ * | | | +--------+
+ * +---->+--------+--------+ | | |
+ * (T2[1w]||ADD2[4w]||ADD1[3w]) | T1 | T0 |----+ | |
+ * +--------+--------+ | | |
+ * ---+--------+--------+<---+ | |
+ * +--- T2| T1 | T0 |----------+
+ * | ---+--------+--------+ | |
+ * | +--------+--------+<-------------+
+ * | | RED2 | RED1 |-----+ | | [0 d1 d0 d1] [d0 0 d1 d0]
+ * | +--------+--------+ | | |
+ * | +--------+<----------------------+
+ * | | RED3 |--------------+ | [0 0 d1 d0]
+ * | +--------+ | |
+ * +--->+--------+--------+ | |
+ * | T1 | T0 |--------+
+ * +--------+--------+ | |
+ * --------------------------- | |
+ * | |
+ * +--------+--------+<----+ |
+ * | RED2 | RED1 | |
+ * +--------+--------+ |
+ * ---+--------+--------+<-------+
+ * T2| T1 | T0 | (H1P-H1P-H00RRAY!)
+ * ---+--------+--------+
+ *
+ * Last 'group' needs to RED2||RED1 shifted less
+ */
+TEXT p256MulInternal<>(SB), NOSPLIT, $0-16
+ // CPOOL loaded from caller
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+ MOVD $96, R21
+ MOVD $112, R22
+
+ MOVD $p256permhilo<>+0x00(SB), EVENODD
+
+ // These values are used by the VMULTxxx macros to
+ // extract the high and low portions of the intermediate
+ // result.
+ LXVD2X (R0)(EVENODD), EXTRACT_LO_
+ LXVD2X (R16)(EVENODD), EXTRACT_HI_
+
+ // ---------------------------------------------------
+
+ VSPLTW $3, Y0, YDIG // VREPF Y0 is input
+
+ // VMLHF X0, YDIG, ADD1H
+ // VMLHF X1, YDIG, ADD2H
+ // VMLF X0, YDIG, ADD1
+ // VMLF X1, YDIG, ADD2
+ //
+ VMULT(X0, YDIG, ADD1, ADD1H)
+ VMULT(X1, YDIG, ADD2, ADD2H)
+
+ VSPLTW $2, Y0, YDIG // VREPF
+
+ // VMALF X0, YDIG, ADD1H, ADD3
+ // VMALF X1, YDIG, ADD2H, ADD4
+ // VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
+ // VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
+ VMULT_ADD(X0, YDIG, ADD1H, ADD3, ADD3H)
+ VMULT_ADD(X1, YDIG, ADD2H, ADD4, ADD4H)
+
+ LXVD2X (R17)(CPOOL), SEL1_
+ VSPLTISB $0, ZER // VZERO ZER
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free // VSLDB
+ VSLDOI $12, ZER, ADD2, T1 // ADD2 Free // VSLDB
+
+ VADDCUQ T0, ADD3, CAR1 // VACCQ
+ VADDUQM T0, ADD3, T0 // ADD3 Free // VAQ
+ VADDECUQ T1, ADD4, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4, CAR1, T1 // ADD4 Free // VACQ
+
+ LXVD2X (R18)(CPOOL), SEL2_
+ LXVD2X (R19)(CPOOL), SEL3_
+ LXVD2X (R20)(CPOOL), SEL4_
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSUBUQM RED2, RED3, RED2 // Guaranteed not to underflow -->? // VSQ
+
+ VSLDOI $12, T1, T0, T0 // VSLDB
+ VSLDOI $12, T2, T1, T1 // VSLDB
+
+ VADDCUQ T0, ADD3H, CAR1 // VACCQ
+ VADDUQM T0, ADD3H, T0 // VAQ
+ VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
+
+ // ---------------------------------------------------
+
+ VSPLTW $1, Y0, YDIG // VREPF
+ LXVD2X (R0)(EVENODD), EXTRACT_LO_
+ LXVD2X (R16)(EVENODD), EXTRACT_HI_
+
+ // VMALHF X0, YDIG, T0, ADD1H
+ // VMALHF X1, YDIG, T1, ADD2H
+ // VMALF X0, YDIG, T0, ADD1 // T0 Free->ADD1
+ // VMALF X1, YDIG, T1, ADD2 // T1 Free->ADD2
+ VMULT_ADD(X0, YDIG, T0, ADD1, ADD1H)
+ VMULT_ADD(X1, YDIG, T1, ADD2, ADD2H)
+
+ VSPLTW $0, Y0, YDIG // VREPF
+
+ // VMALF X0, YDIG, ADD1H, ADD3
+ // VMALF X1, YDIG, ADD2H, ADD4
+ // VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free->ADD3H
+ // VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free->ADD4H , YDIG Free->ZER
+ VMULT_ADD(X0, YDIG, ADD1H, ADD3, ADD3H)
+ VMULT_ADD(X1, YDIG, ADD2H, ADD4, ADD4H)
+
+ VSPLTISB $0, ZER // VZERO ZER
+ LXVD2X (R17)(CPOOL), SEL1_
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free->T0 // VSLDB
+ VSLDOI $12, T2, ADD2, T1 // ADD2 Free->T1, T2 Free // VSLDB
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ
+ VADDUQM T0, RED1, T0 // VAQ
+ VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ
+
+ VADDCUQ T0, ADD3, CAR1 // VACCQ
+ VADDUQM T0, ADD3, T0 // VAQ
+ VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
+ VADDEUQM T1, ADD4, CAR1, T1 // VACQ
+ VADDUQM T2, CAR2, T2 // VAQ
+
+ LXVD2X (R18)(CPOOL), SEL2_
+ LXVD2X (R19)(CPOOL), SEL3_
+ LXVD2X (R20)(CPOOL), SEL4_
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSUBUQM RED2, RED3, RED2 // Guaranteed not to underflow // VSQ
+
+ VSLDOI $12, T1, T0, T0 // VSLDB
+ VSLDOI $12, T2, T1, T1 // VSLDB
+
+ VADDCUQ T0, ADD3H, CAR1 // VACCQ
+ VADDUQM T0, ADD3H, T0 // VAQ
+ VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
+
+ // ---------------------------------------------------
+
+ VSPLTW $3, Y1, YDIG // VREPF
+ LXVD2X (R0)(EVENODD), EXTRACT_LO_
+ LXVD2X (R16)(EVENODD), EXTRACT_HI_
+
+ // VMALHF X0, YDIG, T0, ADD1H
+ // VMALHF X1, YDIG, T1, ADD2H
+ // VMALF X0, YDIG, T0, ADD1
+ // VMALF X1, YDIG, T1, ADD2
+ VMULT_ADD(X0, YDIG, T0, ADD1, ADD1H)
+ VMULT_ADD(X1, YDIG, T1, ADD2, ADD2H)
+
+ VSPLTW $2, Y1, YDIG // VREPF
+
+ // VMALF X0, YDIG, ADD1H, ADD3
+ // VMALF X1, YDIG, ADD2H, ADD4
+ // VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
+ // VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
+ VMULT_ADD(X0, YDIG, ADD1H, ADD3, ADD3H)
+ VMULT_ADD(X1, YDIG, ADD2H, ADD4, ADD4H)
+
+ LXVD2X (R17)(CPOOL), SEL1_
+ VSPLTISB $0, ZER // VZERO ZER
+ LXVD2X (R17)(CPOOL), SEL1_
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free // VSLDB
+ VSLDOI $12, T2, ADD2, T1 // ADD2 Free // VSLDB
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ
+ VADDUQM T0, RED1, T0 // VAQ
+ VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ
+
+ VADDCUQ T0, ADD3, CAR1 // VACCQ
+ VADDUQM T0, ADD3, T0 // VAQ
+ VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
+ VADDEUQM T1, ADD4, CAR1, T1 // VACQ
+ VADDUQM T2, CAR2, T2 // VAQ
+
+ LXVD2X (R18)(CPOOL), SEL2_
+ LXVD2X (R19)(CPOOL), SEL3_
+ LXVD2X (R20)(CPOOL), SEL4_
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSUBUQM RED2, RED3, RED2 // Guaranteed not to underflow // VSQ
+
+ VSLDOI $12, T1, T0, T0 // VSLDB
+ VSLDOI $12, T2, T1, T1 // VSLDB
+
+ VADDCUQ T0, ADD3H, CAR1 // VACCQ
+ VADDUQM T0, ADD3H, T0 // VAQ
+ VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
+
+ // ---------------------------------------------------
+
+ VSPLTW $1, Y1, YDIG // VREPF
+ LXVD2X (R0)(EVENODD), EXTRACT_LO_
+ LXVD2X (R16)(EVENODD), EXTRACT_HI_
+
+ // VMALHF X0, YDIG, T0, ADD1H
+ // VMALHF X1, YDIG, T1, ADD2H
+ // VMALF X0, YDIG, T0, ADD1
+ // VMALF X1, YDIG, T1, ADD2
+ VMULT_ADD(X0, YDIG, T0, ADD1, ADD1H)
+ VMULT_ADD(X1, YDIG, T1, ADD2, ADD2H)
+
+ VSPLTW $0, Y1, YDIG // VREPF
+
+ // VMALF X0, YDIG, ADD1H, ADD3
+ // VMALF X1, YDIG, ADD2H, ADD4
+ // VMALHF X0, YDIG, ADD1H, ADD3H
+ // VMALHF X1, YDIG, ADD2H, ADD4H
+ VMULT_ADD(X0, YDIG, ADD1H, ADD3, ADD3H)
+ VMULT_ADD(X1, YDIG, ADD2H, ADD4, ADD4H)
+
+ VSPLTISB $0, ZER // VZERO ZER
+ LXVD2X (R17)(CPOOL), SEL1_
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDOI $12, ADD2, ADD1, T0 // VSLDB
+ VSLDOI $12, T2, ADD2, T1 // VSLDB
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ
+ VADDUQM T0, RED1, T0 // VAQ
+ VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ
+
+ VADDCUQ T0, ADD3, CAR1 // VACCQ
+ VADDUQM T0, ADD3, T0 // VAQ
+ VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
+ VADDEUQM T1, ADD4, CAR1, T1 // VACQ
+ VADDUQM T2, CAR2, T2 // VAQ
+
+ LXVD2X (R21)(CPOOL), SEL5_
+ LXVD2X (R22)(CPOOL), SEL6_
+ VPERM T0, RED3, SEL5, RED2 // [d1 d0 d1 d0]
+ VPERM T0, RED3, SEL6, RED1 // [ 0 d1 d0 0]
+ VSUBUQM RED2, RED1, RED2 // Guaranteed not to underflow // VSQ
+
+ VSLDOI $12, T1, T0, T0 // VSLDB
+ VSLDOI $12, T2, T1, T1 // VSLDB
+
+ VADDCUQ T0, ADD3H, CAR1 // VACCQ
+ VADDUQM T0, ADD3H, T0 // VAQ
+ VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ
+ VADDUQM T0, RED1, T0 // VAQ
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ
+ VADDUQM T2, CAR2, T2 // VAQ
+
+ // ---------------------------------------------------
+
+ VSPLTISB $0, RED3 // VZERO RED3
+ VSUBCUQ T0, P0, CAR1 // VSCBIQ
+ VSUBUQM T0, P0, ADD1H // VSQ
+ VSUBECUQ T1, P1, CAR1, CAR2 // VSBCBIQ
+ VSUBEUQM T1, P1, CAR1, ADD2H // VSBIQ
+ VSUBEUQM T2, RED3, CAR2, T2 // VSBIQ
+
+ // what output to use, ADD2H||ADD1H or T1||T0?
+ VSEL ADD1H, T0, T2, T0
+ VSEL ADD2H, T1, T2, T1
+ RET
+
+#undef CPOOL
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+
+#undef SEL1
+#undef SEL2
+#undef SEL3
+#undef SEL4
+#undef SEL5
+#undef SEL6
+#undef SEL1_
+#undef SEL2_
+#undef SEL3_
+#undef SEL4_
+#undef SEL5_
+#undef SEL6_
+
+#undef YDIG
+#undef ADD1H
+#undef ADD2H
+#undef ADD3
+#undef ADD4
+#undef RED1
+#undef RED2
+#undef RED3
+#undef T2
+#undef ADD1
+#undef ADD2
+#undef ADD3H
+#undef ADD4H
+#undef ZER
+#undef CAR1
+#undef CAR2
+
+#undef TMP1
+#undef TMP2
+#undef EVENODD
+#undef EXTRACT_HI
+#undef EXTRACT_HI_
+#undef EXTRACT_LO
+#undef EXTRACT_LO_
+
+#define p256SubInternal(T1, T0, X1, X0, Y1, Y0) \
+ VSPLTISB $0, ZER \ // VZERO
+ VSUBCUQ X0, Y0, CAR1 \
+ VSUBUQM X0, Y0, T0 \
+ VSUBECUQ X1, Y1, CAR1, SEL1 \
+ VSUBEUQM X1, Y1, CAR1, T1 \
+ VSUBUQM ZER, SEL1, SEL1 \ // VSQ
+ \
+ VADDCUQ T0, PL, CAR1 \ // VACCQ
+ VADDUQM T0, PL, TT0 \ // VAQ
+ VADDEUQM T1, PH, CAR1, TT1 \ // VACQ
+ \
+ VSEL TT0, T0, SEL1, T0 \
+ VSEL TT1, T1, SEL1, T1 \
+
+#define p256AddInternal(T1, T0, X1, X0, Y1, Y0) \
+ VADDCUQ X0, Y0, CAR1 \
+ VADDUQM X0, Y0, T0 \
+ VADDECUQ X1, Y1, CAR1, T2 \ // VACCCQ
+ VADDEUQM X1, Y1, CAR1, T1 \
+ \
+ VSPLTISB $0, ZER \
+ VSUBCUQ T0, PL, CAR1 \ // VSCBIQ
+ VSUBUQM T0, PL, TT0 \
+ VSUBECUQ T1, PH, CAR1, CAR2 \ // VSBCBIQ
+ VSUBEUQM T1, PH, CAR1, TT1 \ // VSBIQ
+ VSUBEUQM T2, ZER, CAR2, SEL1 \
+ \
+ VSEL TT0, T0, SEL1, T0 \
+ VSEL TT1, T1, SEL1, T1
+
+#define p256HalfInternal(T1, T0, X1, X0) \
+ VSPLTISB $0, ZER \
+ VSUBEUQM ZER, ZER, X0, SEL1 \
+ \
+ VADDCUQ X0, PL, CAR1 \
+ VADDUQM X0, PL, T0 \
+ VADDECUQ X1, PH, CAR1, T2 \
+ VADDEUQM X1, PH, CAR1, T1 \
+ \
+ VSEL T0, X0, SEL1, T0 \
+ VSEL T1, X1, SEL1, T1 \
+ VSEL T2, ZER, SEL1, T2 \
+ \
+ VSLDOI $15, T2, ZER, TT1 \
+ VSLDOI $15, T1, ZER, TT0 \
+ VSPLTISB $1, SEL1 \
+ VSR T0, SEL1, T0 \ // VSRL
+ VSR T1, SEL1, T1 \
+ VSPLTISB $7, SEL1 \ // VREPIB
+ VSL TT0, SEL1, TT0 \
+ VSL TT1, SEL1, TT1 \
+ VOR T0, TT0, T0 \
+ VOR T1, TT1, T1
+
+// ---------------------------------------
+// func p256MulAsm(res, in1, in2 []byte)
+#define res_ptr R3
+#define x_ptr R4
+#define y_ptr R5
+#define CPOOL R7
+#define TEMP R8
+
+// Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+#define X0_ VS32
+#define X1_ VS33
+#define Y0_ VS34
+#define Y1_ VS35
+#define T0_ VS36
+#define T1_ VS37
+#define SWAP V28
+#define SWAP_ VS60
+
+// Constants
+#define P0 V30
+#define P1 V31
+#define P0_ VS62
+#define P1_ VS63
+//
+// Montgomery multiplication modulo P256
+//
+TEXT ·p256MulAsm(SB), NOSPLIT, $0-72
+ MOVD res+0(FP), res_ptr
+ MOVD in1+24(FP), x_ptr
+ MOVD in2+48(FP), y_ptr
+ MOVD $16, R16
+ MOVD $32, R17
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ MOVD $byteswap<>+0x00(SB), R8
+
+ LXVD2X (R8)(R0), SWAP_
+
+ LXVD2X (R0)(x_ptr), X0_
+ LXVD2X (R16)(x_ptr), X1_
+
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+
+ LXVD2X (R0)(y_ptr), Y0_
+ LXVD2X (R16)(y_ptr), Y1_
+
+ VPERM Y0, Y0, SWAP, Y0
+ VPERM Y1, Y1, SWAP, Y1
+
+ LXVD2X (R16)(CPOOL), P1_
+ LXVD2X (R0)(CPOOL), P0_
+
+ CALL p256MulInternal<>(SB)
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ MOVD $byteswap<>+0x00(SB), R8
+
+ LXVD2X (R8)(R0), SWAP_
+
+ VPERM T0, T0, SWAP, T0
+ VPERM T1, T1, SWAP, T1
+ STXVD2X T0_, (R0)(res_ptr)
+ STXVD2X T1_, (R16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef y_ptr
+#undef CPOOL
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+#undef X0_
+#undef X1_
+#undef Y0_
+#undef Y1_
+#undef T0_
+#undef T1_
+#undef P0_
+#undef P1_
+
+// Point add with P2 being affine point
+// If sign == 1 -> P2 = -P2
+// If sel == 0 -> P3 = P1
+// if zero == 0 -> P3 = P2
+// p256PointAddAffineAsm(P3, P1, P2 *p256Point, sign, sel, zero int)
+#define P3ptr R3
+#define P1ptr R4
+#define P2ptr R5
+#define CPOOL R7
+
+// Temporaries in REGs
+#define Y2L V15
+#define Y2H V16
+#define Y2L_ VS47
+#define Y2H_ VS48
+#define T1L V17
+#define T1H V18
+#define T2L V19
+#define T2H V20
+#define T3L V21
+#define T3H V22
+#define T4L V23
+#define T4H V24
+
+// Temps for Sub and Add
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define X0_ VS32
+#define X1_ VS33
+#define Y0 V2
+#define Y1 V3
+#define Y0_ VS34
+#define Y1_ VS35
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+#define PL_ VS62
+#define PH_ VS63
+
+// Names for zero/sel selects
+#define X1L V0
+#define X1H V1
+#define X1L_ VS32
+#define X1H_ VS33
+#define Y1L V2 // p256MulAsmParmY
+#define Y1H V3 // p256MulAsmParmY
+#define Y1L_ VS34
+#define Y1H_ VS35
+#define Z1L V4
+#define Z1H V5
+#define Z1L_ VS36
+#define Z1H_ VS37
+#define X2L V0
+#define X2H V1
+#define X2L_ VS32
+#define X2H_ VS33
+#define Z2L V4
+#define Z2H V5
+#define Z2L_ VS36
+#define Z2H_ VS37
+#define X3L V17 // T1L
+#define X3H V18 // T1H
+#define Y3L V21 // T3L
+#define Y3H V22 // T3H
+#define Z3L V25
+#define Z3H V26
+#define X3L_ VS49
+#define X3H_ VS50
+#define Y3L_ VS53
+#define Y3H_ VS54
+#define Z3L_ VS57
+#define Z3H_ VS58
+
+#define ZER V6
+#define SEL1 V7
+#define SEL1_ VS39
+#define CAR1 V8
+#define CAR2 V9
+/* *
+ * Three operand formula:
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ * T1 = Z1²
+ * T2 = T1*Z1
+ * T1 = T1*X2
+ * T2 = T2*Y2
+ * T1 = T1-X1
+ * T2 = T2-Y1
+ * Z3 = Z1*T1
+ * T3 = T1²
+ * T4 = T3*T1
+ * T3 = T3*X1
+ * T1 = 2*T3
+ * X3 = T2²
+ * X3 = X3-T1
+ * X3 = X3-T4
+ * T3 = T3-X3
+ * T3 = T3*T2
+ * T4 = T4*Y1
+ * Y3 = T3-T4
+
+ * Three operand formulas, but with MulInternal X,Y used to store temps
+X=Z1; Y=Z1; MUL;T- // T1 = Z1² T1
+X=T ; Y- ; MUL;T2=T // T2 = T1*Z1 T1 T2
+X- ; Y=X2; MUL;T1=T // T1 = T1*X2 T1 T2
+X=T2; Y=Y2; MUL;T- // T2 = T2*Y2 T1 T2
+SUB(T2+0x00(SB), CPOOL
+
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+ MOVD $96, R21
+ MOVD $112, R22
+ MOVD $128, R23
+ MOVD $144, R24
+ MOVD $160, R25
+ MOVD $104, R26 // offset of sign+24(FP)
+
+ MOVD $byteswap<>+0+00(SB), R8
+ LXVD2X (R16)(CPOOL), PH_
+ LXVD2X (R0)(CPOOL), PL_
+
+ // if (sign == 1) {
+ // Y2 = fromBig(new(big.Int).Mod(new(big.Int).Sub(p256.P, new(big.Int).SetBytes(Y2)), p256.P)) // Y2 = P-Y2
+ // }
+
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R17)(P2ptr), Y2L_
+ LXVD2X (R18)(P2ptr), Y2H_
+ VPERM Y2H, Y2H, SWAP, Y2H
+ VPERM Y2L, Y2L, SWAP, Y2L
+
+ // Equivalent of VLREPG sign+24(FP), SEL1
+ LXVDSX (R1)(R26), SEL1_
+ VSPLTISB $0, ZER
+ VCMPEQUD SEL1, ZER, SEL1
+
+ VSUBCUQ PL, Y2L, CAR1
+ VSUBUQM PL, Y2L, T1L
+ VSUBEUQM PH, Y2H, CAR1, T1H
+
+ VSEL T1L, Y2L, SEL1, Y2L
+ VSEL T1H, Y2H, SEL1, Y2H
+
+/* *
+ * Three operand formula:
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ */
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1² T1
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R19)(P1ptr), X0_ // Z1H
+ LXVD2X (R20)(P1ptr), X1_ // Z1L
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y- ; MUL; T2=T // T2 = T1*Z1 T1 T2
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T2L
+ VOR T1, T1, T2H
+
+ // X- ; Y=X2; MUL; T1=T // T1 = T1*X2 T1 T2
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R0)(P2ptr), Y0_ // X2H
+ LXVD2X (R16)(P2ptr), Y1_ // X2L
+ VPERM Y0, Y0, SWAP, Y0
+ VPERM Y1, Y1, SWAP, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T1L
+ VOR T1, T1, T1H
+
+ // X=T2; Y=Y2; MUL; T- // T2 = T2*Y2 T1 T2
+ VOR T2L, T2L, X0
+ VOR T2H, T2H, X1
+ VOR Y2L, Y2L, Y0
+ VOR Y2H, Y2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T2(SB)
+
+ // VST T1, 64(P3ptr)
+ // VST T0, 80(P3ptr)
+ VOR T0, T0, Z3L
+ VOR T1, T1, Z3H
+
+ // X=Y; Y- ; MUL; X=T // T3 = T1*T1 T2
+ VOR Y0, Y0, X0
+ VOR Y1, Y1, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+
+ // X- ; Y- ; MUL; T4=T // T4 = T3*T1 T2 T4
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T4L
+ VOR T1, T1, T4H
+
+ // X- ; Y=X1; MUL; T3=T // T3 = T3*X1 T2 T3 T4
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R0)(P1ptr), Y0_ // X1H
+ LXVD2X (R16)(P1ptr), Y1_ // X1L
+ VPERM Y1, Y1, SWAP, Y1
+ VPERM Y0, Y0, SWAP, Y0
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T3L
+ VOR T1, T1, T3H
+
+ // ADD(T1(SB)
+
+ // SUB(T(SB)
+ VOR T0, T0, T3L
+ VOR T1, T1, T3H
+
+ // X=T4; Y=Y1; MUL; T- // T4 = T4*Y1 T3 T4
+ VOR T4L, T4L, X0
+ VOR T4H, T4H, X1
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R17)(P1ptr), Y0_ // Y1H
+ LXVD2X (R18)(P1ptr), Y1_ // Y1L
+ VPERM Y0, Y0, SWAP, Y0
+ VPERM Y1, Y1, SWAP, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T+0x00(SB), CPOOL
+ MOVD $byteswap<>+0x00(SB), R15
+
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+
+ LXVD2X (R16)(CPOOL), PH_
+ LXVD2X (R0)(CPOOL), PL_
+
+ LXVD2X (R15)(R0), SWAP_
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1²
+ LXVD2X (R19)(P1ptr), X0_ // Z1H
+ LXVD2X (R20)(P1ptr), X1_ // Z1L
+
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(X(SB)
+
+ // ADD(T2(SB)
+
+ LXVD2X (R15)(R0), SWAP_
+
+ // Leave T0, T1 as is.
+ VPERM T0, T0, SWAP, TT0
+ VPERM T1, T1, SWAP, TT1
+ STXVD2X TT0_, (R19)(P3ptr)
+ STXVD2X TT1_, (R20)(P3ptr)
+
+ // X- ; Y=X ; MUL; T- // Y3 = Y3²
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y=X1; MUL; T3=T // T3 = Y3*X1
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+ LXVD2X (R15)(R0), SWAP_
+ LXVD2X (R0)(P1ptr), Y0_
+ LXVD2X (R16)(P1ptr), Y1_
+ VPERM Y0, Y0, SWAP, Y0
+ VPERM Y1, Y1, SWAP, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T3L
+ VOR T1, T1, T3H
+
+ // X- ; Y=X ; MUL; T- // Y3 = Y3²
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // HAL(Y3(SB)
+
+ // ADD(T1(SB)
+
+ // SUB(Y3+0x00(SB), CPOOL
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+
+ MOVD $byteswap<>+0x00(SB), R8
+ LXVD2X (R16)(CPOOL), PH_
+ LXVD2X (R0)(CPOOL), PL_
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1*Z1
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R19)(P1ptr), X0_ // Z1L
+ LXVD2X (R20)(P1ptr), X1_ // Z1H
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X- ; Y=T ; MUL; R=T // R = Z1*T1
+ VOR T0, T0, Y0
+ VOR T1, T1, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, RL // SAVE: RL
+ VOR T1, T1, RH // SAVE: RH
+
+ STXVD2X RH_, (R1)(R17) // V27 has to be saved
+
+ // X=X2; Y- ; MUL; H=T // H = X2*T1
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R0)(P2ptr), X0_ // X2L
+ LXVD2X (R16)(P2ptr), X1_ // X2H
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, HL // SAVE: HL
+ VOR T1, T1, HH // SAVE: HH
+
+ // X=Z2; Y=Z2; MUL; T- // T2 = Z2*Z2
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R19)(P2ptr), X0_ // Z2L
+ LXVD2X (R20)(P2ptr), X1_ // Z2H
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X- ; Y=T ; MUL; S1=T // S1 = Z2*T2
+ VOR T0, T0, Y0
+ VOR T1, T1, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, S1L // SAVE: S1L
+ VOR T1, T1, S1H // SAVE: S1H
+
+ // X=X1; Y- ; MUL; U1=T // U1 = X1*T2
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R0)(P1ptr), X0_ // X1L
+ LXVD2X (R16)(P1ptr), X1_ // X1H
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, U1L // SAVE: U1L
+ VOR T1, T1, U1H // SAVE: U1H
+
+ // SUB(H+0x00(SB), R8
+ MOVD in1+8(FP), P1ptr
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R19)(P1ptr), X0_ // Z1L
+ LXVD2X (R20)(P1ptr), X1_ // Z1H
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+ LXVD2X (R19)(P2ptr), Y0_ // Z2L
+ LXVD2X (R20)(P2ptr), Y1_ // Z2H
+ VPERM Y0, Y0, SWAP, Y0
+ VPERM Y1, Y1, SWAP, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+ VOR HL, HL, Y0
+ VOR HH, HH, Y1
+ CALL p256MulInternal<>(SB)
+ MOVD res+0(FP), P3ptr
+ LXVD2X (R8)(R0), SWAP_
+ VPERM T1, T1, SWAP, TT1
+ VPERM T0, T0, SWAP, TT0
+ STXVD2X TT0_, (R19)(P3ptr)
+ STXVD2X TT1_, (R20)(P3ptr)
+
+ // X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R17)(P1ptr), X0_
+ LXVD2X (R18)(P1ptr), X1_
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+ VOR S1L, S1L, Y0
+ VOR S1H, S1H, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, S1L
+ VOR T1, T1, S1H
+
+ // X=Y2; Y=R ; MUL; T- // R = Y2*R
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R8)(R0), SWAP_
+ LXVD2X (R17)(P2ptr), X0_
+ LXVD2X (R18)(P2ptr), X1_
+ VPERM X0, X0, SWAP, X0
+ VPERM X1, X1, SWAP, X1
+ VOR RL, RL, Y0
+
+ // VOR RH, RH, Y1 RH was saved above in D2X format
+ LXVD2X (R1)(R17), Y1_
+ CALL p256MulInternal<>(SB)
+
+ // SUB(R(SB)
+
+ // X- ; Y=T ; MUL; T2=T // T2 = H*T1
+ VOR T0, T0, Y0
+ VOR T1, T1, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T2L
+ VOR T1, T1, T2H
+
+ // X=U1; Y- ; MUL; U1=T // U1 = U1*T1
+ VOR U1L, U1L, X0
+ VOR U1H, U1H, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, U1L
+ VOR T1, T1, U1H
+
+ // X=R ; Y=R ; MUL; T- // X3 = R*R
+ VOR RL, RL, X0
+
+ // VOR RH, RH, X1
+ VOR RL, RL, Y0
+
+ // RH was saved above using STXVD2X
+ LXVD2X (R1)(R17), X1_
+ VOR X1, X1, Y1
+
+ // VOR RH, RH, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T(SB)
+ VOR T0, T0, U1L
+ VOR T1, T1, U1H
+
+ // X=S1; Y=T2; MUL; T- // T2 = S1*T2
+ VOR S1L, S1L, X0
+ VOR S1H, S1H, X1
+ VOR T2L, T2L, Y0
+ VOR T2H, T2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T P2 = -P2
+// If sel == 0 -> P3 = P1
+// if zero == 0 -> P3 = P2
+//
+//go:noescape
+func p256PointAddAffineAsm(res, in1, in2 *p256Point, sign, sel, zero int)
+
+// Point add
+//
+//go:noescape
+func p256PointAddAsm(res, in1, in2 *p256Point) int
+
+//
+//go:noescape
+func p256PointDoubleAsm(res, in *p256Point)
+
+// The result should be a slice in LE order, but the slice
+// from big.Bytes is in BE order.
+// TODO: For big endian implementation, do not reverse bytes.
+//
+func fromBig(big *big.Int) []byte {
+ // This could be done a lot more efficiently...
+ res := big.Bytes()
+ t := make([]byte, 32)
+ if len(res) < 32 {
+ copy(t[32-len(res):], res)
+ } else if len(res) == 32 {
+ copy(t, res)
+ } else {
+ copy(t, res[len(res)-32:])
+ }
+ p256ReverseBytes(t, t)
+ return t
+}
+
+// p256GetMultiplier makes sure byte array will have 32 byte elements, If the scalar
+// is equal or greater than the order of the group, it's reduced modulo that order.
+func p256GetMultiplier(in []byte) []byte {
+ n := new(big.Int).SetBytes(in)
+
+ if n.Cmp(p256Params.N) >= 0 {
+ n.Mod(n, p256Params.N)
+ }
+ return fromBig(n)
+}
+
+// p256MulAsm operates in a Montgomery domain with R = 2^256 mod p, where p is the
+// underlying field of the curve. (See initP256 for the value.) Thus rr here is
+// R×R mod p. See comment in Inverse about how this is used.
+// TODO: For big endian implementation, the bytes in these slices should be in reverse order,
+// as found in the s390x implementation.
+var rr = []byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00}
+
+// (This is one, in the Montgomery domain.)
+var one = []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}
+
+func maybeReduceModP(in *big.Int) *big.Int {
+ if in.Cmp(p256Params.P) < 0 {
+ return in
+ }
+ return new(big.Int).Mod(in, p256Params.P)
+}
+
+func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
+ var r1, r2 p256Point
+
+ scalarReduced := p256GetMultiplier(baseScalar)
+ r1IsInfinity := scalarIsZero(scalarReduced)
+ r1.p256BaseMult(scalarReduced)
+
+ copy(r2.x[:], fromBig(maybeReduceModP(bigX)))
+ copy(r2.y[:], fromBig(maybeReduceModP(bigY)))
+ copy(r2.z[:], one)
+ p256MulAsm(r2.x[:], r2.x[:], rr[:])
+ p256MulAsm(r2.y[:], r2.y[:], rr[:])
+
+ scalarReduced = p256GetMultiplier(scalar)
+ r2IsInfinity := scalarIsZero(scalarReduced)
+ r2.p256ScalarMult(scalarReduced)
+
+ var sum, double p256Point
+ pointsEqual := p256PointAddAsm(&sum, &r1, &r2)
+ p256PointDoubleAsm(&double, &r1)
+ p256MovCond(&sum, &double, &sum, pointsEqual)
+ p256MovCond(&sum, &r1, &sum, r2IsInfinity)
+ p256MovCond(&sum, &r2, &sum, r1IsInfinity)
+ return sum.p256PointToAffine()
+}
+
+func (curve p256CurveFast) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
+ var r p256Point
+ reducedScalar := p256GetMultiplier(scalar)
+ r.p256BaseMult(reducedScalar)
+ return r.p256PointToAffine()
+}
+
+func (curve p256CurveFast) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
+ scalarReduced := p256GetMultiplier(scalar)
+ var r p256Point
+ copy(r.x[:], fromBig(maybeReduceModP(bigX)))
+ copy(r.y[:], fromBig(maybeReduceModP(bigY)))
+ copy(r.z[:], one)
+ p256MulAsm(r.x[:], r.x[:], rr[:])
+ p256MulAsm(r.y[:], r.y[:], rr[:])
+ r.p256ScalarMult(scalarReduced)
+ return r.p256PointToAffine()
+}
+
+func scalarIsZero(scalar []byte) int {
+ // If any byte is not zero, return 0.
+ // Check for -0.... since that appears to compare to 0.
+ b := byte(0)
+ for _, s := range scalar {
+ b |= s
+ }
+ return subtle.ConstantTimeByteEq(b, 0)
+}
+
+func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
+ zInv := make([]byte, 32)
+ zInvSq := make([]byte, 32)
+
+ p256Inverse(zInv, p.z[:])
+ p256Sqr(zInvSq, zInv)
+ p256MulAsm(zInv, zInv, zInvSq)
+
+ p256MulAsm(zInvSq, p.x[:], zInvSq)
+ p256MulAsm(zInv, p.y[:], zInv)
+
+ p256FromMont(zInvSq, zInvSq)
+ p256FromMont(zInv, zInv)
+
+ // SetBytes expects a slice in big endian order,
+ // since ppc64le is little endian, reverse the bytes.
+ // TODO: For big endian, bytes don't need to be reversed.
+ p256ReverseBytes(zInvSq, zInvSq)
+ p256ReverseBytes(zInv, zInv)
+ rx := new(big.Int).SetBytes(zInvSq)
+ ry := new(big.Int).SetBytes(zInv)
+ return rx, ry
+}
+
+// p256Inverse sets out to in^-1 mod p.
+func p256Inverse(out, in []byte) {
+ var stack [6 * 32]byte
+ p2 := stack[32*0 : 32*0+32]
+ p4 := stack[32*1 : 32*1+32]
+ p8 := stack[32*2 : 32*2+32]
+ p16 := stack[32*3 : 32*3+32]
+ p32 := stack[32*4 : 32*4+32]
+
+ p256Sqr(out, in)
+ p256MulAsm(p2, out, in) // 3*p
+
+ p256Sqr(out, p2)
+ p256Sqr(out, out)
+ p256MulAsm(p4, out, p2) // f*p
+
+ p256Sqr(out, p4)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(p8, out, p4) // ff*p
+
+ p256Sqr(out, p8)
+
+ for i := 0; i < 7; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(p16, out, p8) // ffff*p
+
+ p256Sqr(out, p16)
+ for i := 0; i < 15; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(p32, out, p16) // ffffffff*p
+
+ p256Sqr(out, p32)
+
+ for i := 0; i < 31; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, in)
+
+ for i := 0; i < 32*4; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p32)
+
+ for i := 0; i < 32; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p32)
+
+ for i := 0; i < 16; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p16)
+
+ for i := 0; i < 8; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p8)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, p4)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, p2)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, in)
+}
+
+func boothW5(in uint) (int, int) {
+ var s uint = ^((in >> 5) - 1)
+ var d uint = (1 << 6) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func boothW6(in uint) (int, int) {
+ var s uint = ^((in >> 6) - 1)
+ var d uint = (1 << 7) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func boothW7(in uint) (int, int) {
+ var s uint = ^((in >> 7) - 1)
+ var d uint = (1 << 8) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func initTable() {
+
+ p256PreFast = new([37][64]p256Point)
+
+ // TODO: For big endian, these slices should be in reverse byte order,
+ // as found in the s390x implementation.
+ basePoint := p256Point{
+ x: [32]byte{0x3c, 0x14, 0xa9, 0x18, 0xd4, 0x30, 0xe7, 0x79, 0x01, 0xb6, 0xed, 0x5f, 0xfc, 0x95, 0xba, 0x75,
+ 0x10, 0x25, 0x62, 0x77, 0x2b, 0x73, 0xfb, 0x79, 0xc6, 0x55, 0x37, 0xa5, 0x76, 0x5f, 0x90, 0x18}, //(p256.x*2^256)%p
+ y: [32]byte{0x0a, 0x56, 0x95, 0xce, 0x57, 0x53, 0xf2, 0xdd, 0x5c, 0xe4, 0x19, 0xba, 0xe4, 0xb8, 0x4a, 0x8b,
+ 0x25, 0xf3, 0x21, 0xdd, 0x88, 0x86, 0xe8, 0xd2, 0x85, 0x5d, 0x88, 0x25, 0x18, 0xff, 0x71, 0x85}, //(p256.y*2^256)%p
+ z: [32]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, //(p256.z*2^256)%p
+
+ }
+
+ t1 := new(p256Point)
+ t2 := new(p256Point)
+ *t2 = basePoint
+
+ zInv := make([]byte, 32)
+ zInvSq := make([]byte, 32)
+ for j := 0; j < 64; j++ {
+ *t1 = *t2
+ for i := 0; i < 37; i++ {
+ // The window size is 7 so we need to double 7 times.
+ if i != 0 {
+ for k := 0; k < 7; k++ {
+ p256PointDoubleAsm(t1, t1)
+ }
+ }
+ // Convert the point to affine form. (Its values are
+ // still in Montgomery form however.)
+ p256Inverse(zInv, t1.z[:])
+ p256Sqr(zInvSq, zInv)
+ p256MulAsm(zInv, zInv, zInvSq)
+
+ p256MulAsm(t1.x[:], t1.x[:], zInvSq)
+ p256MulAsm(t1.y[:], t1.y[:], zInv)
+
+ copy(t1.z[:], basePoint.z[:])
+ // Update the table entry
+ copy(p256PreFast[i][j].x[:], t1.x[:])
+ copy(p256PreFast[i][j].y[:], t1.y[:])
+ }
+ if j == 0 {
+ p256PointDoubleAsm(t2, &basePoint)
+ } else {
+ p256PointAddAsm(t2, t2, &basePoint)
+ }
+ }
+}
+
+func (p *p256Point) p256BaseMult(scalar []byte) {
+ // TODO: For big endian, the index should be 31 not 0.
+ wvalue := (uint(scalar[0]) << 1) & 0xff
+ sel, sign := boothW7(uint(wvalue))
+ p256SelectBase(p, p256PreFast[0][:], sel)
+ p256NegCond(p, sign)
+
+ copy(p.z[:], one[:])
+ var t0 p256Point
+
+ copy(t0.z[:], one[:])
+
+ index := uint(6)
+ zero := sel
+ for i := 1; i < 37; i++ {
+ // TODO: For big endian, use the same index values as found
+ // in the s390x implementation.
+ if index < 247 {
+ wvalue = ((uint(scalar[index/8]) >> (index % 8)) + (uint(scalar[index/8+1]) << (8 - (index % 8)))) & 0xff
+ } else {
+ wvalue = (uint(scalar[index/8]) >> (index % 8)) & 0xff
+ }
+ index += 7
+ sel, sign = boothW7(uint(wvalue))
+ p256SelectBase(&t0, p256PreFast[i][:], sel)
+ p256PointAddAffineAsm(p, p, &t0, sign, sel, zero)
+ zero |= sel
+ }
+}
+
+func (p *p256Point) p256ScalarMult(scalar []byte) {
+ // precomp is a table of precomputed points that stores powers of p
+ // from p^1 to p^16.
+ var precomp [16]p256Point
+ var t0, t1, t2, t3 p256Point
+
+ *&precomp[0] = *p
+ p256PointDoubleAsm(&t0, p)
+ p256PointDoubleAsm(&t1, &t0)
+ p256PointDoubleAsm(&t2, &t1)
+ p256PointDoubleAsm(&t3, &t2)
+ *&precomp[1] = t0
+ *&precomp[3] = t1
+ *&precomp[7] = t2
+ *&precomp[15] = t3
+
+ p256PointAddAsm(&t0, &t0, p)
+ p256PointAddAsm(&t1, &t1, p)
+ p256PointAddAsm(&t2, &t2, p)
+
+ *&precomp[2] = t0
+ *&precomp[4] = t1
+ *&precomp[8] = t2
+
+ p256PointDoubleAsm(&t0, &t0)
+ p256PointDoubleAsm(&t1, &t1)
+ *&precomp[5] = t0
+ *&precomp[9] = t1
+
+ p256PointAddAsm(&t2, &t0, p)
+ p256PointAddAsm(&t1, &t1, p)
+ *&precomp[6] = t2
+ *&precomp[10] = t1
+
+ p256PointDoubleAsm(&t0, &t0)
+ p256PointDoubleAsm(&t2, &t2)
+ *&precomp[11] = t0
+ *&precomp[13] = t2
+
+ p256PointAddAsm(&t0, &t0, p)
+ p256PointAddAsm(&t2, &t2, p)
+ *&precomp[12] = t0
+ *&precomp[14] = t2
+
+ // Start scanning the window from top bit
+ index := uint(254)
+ var sel, sign int
+
+ // TODO: For big endian, use index found in s390x implementation.
+ wvalue := (uint(scalar[index/8]) >> (index % 8)) & 0x3f
+ sel, _ = boothW5(uint(wvalue))
+ p256Select(p, precomp[:], sel)
+ zero := sel
+
+ for index > 4 {
+ index -= 5
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+
+ // TODO: For big endian, use index values as found in s390x implementation.
+ if index < 247 {
+ wvalue = ((uint(scalar[index/8]) >> (index % 8)) + (uint(scalar[index/8+1]) << (8 - (index % 8)))) & 0x3f
+ } else {
+ wvalue = (uint(scalar[index/8]) >> (index % 8)) & 0x3f
+ }
+
+ sel, sign = boothW5(uint(wvalue))
+
+ p256Select(&t0, precomp[:], sel)
+ p256NegCond(&t0, sign)
+ p256PointAddAsm(&t1, p, &t0)
+ p256MovCond(&t1, &t1, p, sel)
+ p256MovCond(p, &t1, &t0, zero)
+ zero |= sel
+ }
+
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+
+ // TODO: Use index for big endian as found in s390x implementation.
+ wvalue = (uint(scalar[0]) << 1) & 0x3f
+ sel, sign = boothW5(uint(wvalue))
+
+ p256Select(&t0, precomp[:], sel)
+ p256NegCond(&t0, sign)
+ p256PointAddAsm(&t1, p, &t0)
+ p256MovCond(&t1, &t1, p, sel)
+ p256MovCond(p, &t1, &t0, zero)
+}
--
cgit v1.3-5-g9baa
From 0ae9389609f23dc905c58fc2ad7bcc16b770f337 Mon Sep 17 00:00:00 2001
From: Lynn Boger
Date: Mon, 28 Oct 2019 09:29:40 -0400
Subject: runtime: fix textOff for multiple text sections
If a compilation has multiple text sections, code in
textOff must compare the offset argument against the range
for each text section to determine which one it is in.
The comparison looks like this:
if uintptr(off) >= sectaddr && uintptr(off) <= sectaddr+sectlen
If the off value being compared is equal to sectaddr+sectlen then it
is not within the range of the text section but after it. The
comparison should be just '<'.
Updates #35207
Change-Id: I114633fd734563d38f4e842dd884c6c239f73c95
Reviewed-on: https://go-review.googlesource.com/c/go/+/203817
Run-TryBot: Lynn Boger
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
Reviewed-by: Cherry Zhang
---
src/runtime/type.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/runtime/type.go b/src/runtime/type.go
index af1fa2e1ca..52b6cb30b4 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -292,7 +292,7 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
for i := range md.textsectmap {
sectaddr := md.textsectmap[i].vaddr
sectlen := md.textsectmap[i].length
- if uintptr(off) >= sectaddr && uintptr(off) <= sectaddr+sectlen {
+ if uintptr(off) >= sectaddr && uintptr(off) < sectaddr+sectlen {
res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
break
}
--
cgit v1.3-5-g9baa
From 503bccb5d91998e22e32c6f771262ed33b72ff8b Mon Sep 17 00:00:00 2001
From: Cherry Zhang
Date: Fri, 25 Oct 2019 16:43:08 -0400
Subject: cmd/compile: delete ZeroAuto
ZeroAuto was used with the ambiguously live logic. The
ambiguously live logic is removed as we switched to stack
objects. It is now never called. Remove.
Change-Id: If4cdd7fed5297f8ab591cc392a76c80f57820856
Reviewed-on: https://go-review.googlesource.com/c/go/+/203538
Run-TryBot: Cherry Zhang
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/cmd/compile/internal/amd64/galign.go | 1 -
src/cmd/compile/internal/amd64/ggen.go | 20 --------------------
src/cmd/compile/internal/arm/galign.go | 1 -
src/cmd/compile/internal/arm/ggen.go | 21 ---------------------
src/cmd/compile/internal/arm64/galign.go | 1 -
src/cmd/compile/internal/arm64/ggen.go | 16 ----------------
src/cmd/compile/internal/gc/go.go | 5 -----
src/cmd/compile/internal/mips/galign.go | 1 -
src/cmd/compile/internal/mips/ggen.go | 16 ----------------
src/cmd/compile/internal/mips64/galign.go | 1 -
src/cmd/compile/internal/mips64/ggen.go | 16 ----------------
src/cmd/compile/internal/ppc64/galign.go | 1 -
src/cmd/compile/internal/ppc64/ggen.go | 16 ----------------
src/cmd/compile/internal/s390x/galign.go | 1 -
src/cmd/compile/internal/s390x/ggen.go | 17 -----------------
src/cmd/compile/internal/wasm/ssa.go | 16 ----------------
src/cmd/compile/internal/x86/galign.go | 1 -
src/cmd/compile/internal/x86/ggen.go | 16 ----------------
18 files changed, 167 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go
index 4e7e762d7d..af58440502 100644
--- a/src/cmd/compile/internal/amd64/galign.go
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -17,7 +17,6 @@ func Init(arch *gc.Arch) {
arch.MAXWIDTH = 1 << 50
arch.ZeroRange = zerorange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnop
diff --git a/src/cmd/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go
index f43800efe7..0c1456f4d0 100644
--- a/src/cmd/compile/internal/amd64/ggen.go
+++ b/src/cmd/compile/internal/amd64/ggen.go
@@ -121,26 +121,6 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj.Pr
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- // Note: this code must not clobber any registers.
- op := x86.AMOVQ
- if gc.Widthptr == 4 {
- op = x86.AMOVL
- }
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- for i := int64(0); i < size; i += int64(gc.Widthptr) {
- p := pp.Prog(op)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_AUTO
- p.To.Reg = x86.REG_SP
- p.To.Offset = n.Xoffset + i
- p.To.Sym = sym
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
// This is a hardware nop (1-byte 0x90) instruction,
// even though we describe it as an explicit XCHGL here.
diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go
index 8469dbdd73..20e2f43a91 100644
--- a/src/cmd/compile/internal/arm/galign.go
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -17,7 +17,6 @@ func Init(arch *gc.Arch) {
arch.MAXWIDTH = (1 << 32) - 1
arch.SoftFloat = objabi.GOARM == 5
arch.ZeroRange = zerorange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnop
diff --git a/src/cmd/compile/internal/arm/ggen.go b/src/cmd/compile/internal/arm/ggen.go
index e9a92af108..bd8d7ff40b 100644
--- a/src/cmd/compile/internal/arm/ggen.go
+++ b/src/cmd/compile/internal/arm/ggen.go
@@ -47,27 +47,6 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, r0 *uint32) *obj.Prog
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- // Note: this code must not clobber any registers.
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- p := pp.Prog(arm.AMOVW)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = arm.REGTMP
- for i := int64(0); i < size; i += 4 {
- p := pp.Prog(arm.AMOVW)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = arm.REGTMP
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_AUTO
- p.To.Reg = arm.REGSP
- p.To.Offset = n.Xoffset + i
- p.To.Sym = sym
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
p := pp.Prog(arm.AAND)
p.From.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go
index f01fe8a571..40d6e17ae2 100644
--- a/src/cmd/compile/internal/arm64/galign.go
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -17,7 +17,6 @@ func Init(arch *gc.Arch) {
arch.PadFrame = padframe
arch.ZeroRange = zerorange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnop
diff --git a/src/cmd/compile/internal/arm64/ggen.go b/src/cmd/compile/internal/arm64/ggen.go
index 2f925656bc..dbe7495cca 100644
--- a/src/cmd/compile/internal/arm64/ggen.go
+++ b/src/cmd/compile/internal/arm64/ggen.go
@@ -63,22 +63,6 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- // Note: this code must not clobber any registers.
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- for i := int64(0); i < size; i += 8 {
- p := pp.Prog(arm64.AMOVD)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = arm64.REGZERO
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_AUTO
- p.To.Reg = arm64.REGSP
- p.To.Offset = n.Xoffset + i
- p.To.Sym = sym
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
p := pp.Prog(arm64.AHINT)
p.From.Type = obj.TYPE_CONST
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index d05f754f30..c14fb4d3fa 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -270,11 +270,6 @@ type Arch struct {
// SSAGenBlock emits end-of-block Progs. SSAGenValue should be called
// for all values in the block before SSAGenBlock.
SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
-
- // ZeroAuto emits code to zero the given auto stack variable.
- // ZeroAuto must not use any non-temporary registers.
- // ZeroAuto will only be called for variables which contain a pointer.
- ZeroAuto func(*Progs, *Node)
}
var thearch Arch
diff --git a/src/cmd/compile/internal/mips/galign.go b/src/cmd/compile/internal/mips/galign.go
index 596dbd7fa0..be40c16dde 100644
--- a/src/cmd/compile/internal/mips/galign.go
+++ b/src/cmd/compile/internal/mips/galign.go
@@ -20,7 +20,6 @@ func Init(arch *gc.Arch) {
arch.MAXWIDTH = (1 << 31) - 1
arch.SoftFloat = (objabi.GOMIPS == "softfloat")
arch.ZeroRange = zerorange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnop
arch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
diff --git a/src/cmd/compile/internal/mips/ggen.go b/src/cmd/compile/internal/mips/ggen.go
index eab60756ba..5e867721c3 100644
--- a/src/cmd/compile/internal/mips/ggen.go
+++ b/src/cmd/compile/internal/mips/ggen.go
@@ -43,22 +43,6 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- // Note: this code must not clobber any registers.
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- for i := int64(0); i < size; i += 4 {
- p := pp.Prog(mips.AMOVW)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = mips.REGZERO
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_AUTO
- p.To.Reg = mips.REGSP
- p.To.Offset = n.Xoffset + i
- p.To.Sym = sym
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
p := pp.Prog(mips.ANOR)
p.From.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go
index 07e9f98be5..90c381a50b 100644
--- a/src/cmd/compile/internal/mips64/galign.go
+++ b/src/cmd/compile/internal/mips64/galign.go
@@ -20,7 +20,6 @@ func Init(arch *gc.Arch) {
arch.MAXWIDTH = 1 << 50
arch.SoftFloat = objabi.GOMIPS64 == "softfloat"
arch.ZeroRange = zerorange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnop
diff --git a/src/cmd/compile/internal/mips64/ggen.go b/src/cmd/compile/internal/mips64/ggen.go
index 80c1f0296c..04e7a66e41 100644
--- a/src/cmd/compile/internal/mips64/ggen.go
+++ b/src/cmd/compile/internal/mips64/ggen.go
@@ -47,22 +47,6 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- // Note: this code must not clobber any registers.
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- for i := int64(0); i < size; i += 8 {
- p := pp.Prog(mips.AMOVV)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = mips.REGZERO
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_AUTO
- p.To.Reg = mips.REGSP
- p.To.Offset = n.Xoffset + i
- p.To.Sym = sym
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
p := pp.Prog(mips.ANOR)
p.From.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go
index c6866e65e7..c8ef567dc3 100644
--- a/src/cmd/compile/internal/ppc64/galign.go
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -19,7 +19,6 @@ func Init(arch *gc.Arch) {
arch.MAXWIDTH = 1 << 60
arch.ZeroRange = zerorange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnopdefer
diff --git a/src/cmd/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go
index a63a0f0f77..a5a772b491 100644
--- a/src/cmd/compile/internal/ppc64/ggen.go
+++ b/src/cmd/compile/internal/ppc64/ggen.go
@@ -42,22 +42,6 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- // Note: this code must not clobber any registers.
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- for i := int64(0); i < size; i += 8 {
- p := pp.Prog(ppc64.AMOVD)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = ppc64.REGZERO
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_AUTO
- p.To.Reg = ppc64.REGSP
- p.To.Offset = n.Xoffset + i
- p.To.Sym = sym
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
p := pp.Prog(ppc64.AOR)
p.From.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/s390x/galign.go b/src/cmd/compile/internal/s390x/galign.go
index 26359abe66..cb68fd36c1 100644
--- a/src/cmd/compile/internal/s390x/galign.go
+++ b/src/cmd/compile/internal/s390x/galign.go
@@ -15,7 +15,6 @@ func Init(arch *gc.Arch) {
arch.MAXWIDTH = 1 << 50
arch.ZeroRange = zerorange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnop
diff --git a/src/cmd/compile/internal/s390x/ggen.go b/src/cmd/compile/internal/s390x/ggen.go
index 16af190b2f..5a837d8574 100644
--- a/src/cmd/compile/internal/s390x/ggen.go
+++ b/src/cmd/compile/internal/s390x/ggen.go
@@ -83,23 +83,6 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- // Note: this code must not clobber any registers or the
- // condition code.
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- for i := int64(0); i < size; i += int64(gc.Widthptr) {
- p := pp.Prog(s390x.AMOVD)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_AUTO
- p.To.Reg = s390x.REGSP
- p.To.Offset = n.Xoffset + i
- p.To.Sym = sym
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
return pp.Prog(s390x.ANOPH)
}
diff --git a/src/cmd/compile/internal/wasm/ssa.go b/src/cmd/compile/internal/wasm/ssa.go
index 75b306e168..e075892348 100644
--- a/src/cmd/compile/internal/wasm/ssa.go
+++ b/src/cmd/compile/internal/wasm/ssa.go
@@ -19,7 +19,6 @@ func Init(arch *gc.Arch) {
arch.MAXWIDTH = 1 << 50
arch.ZeroRange = zeroRange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnop
@@ -45,21 +44,6 @@ func zeroRange(pp *gc.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj.Pr
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- for i := int64(0); i < size; i += 8 {
- p := pp.Prog(wasm.AGet)
- p.From = obj.Addr{Type: obj.TYPE_REG, Reg: wasm.REG_SP}
-
- p = pp.Prog(wasm.AI64Const)
- p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
-
- p = pp.Prog(wasm.AI64Store)
- p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: n.Xoffset + i, Sym: sym}
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
return pp.Prog(wasm.ANop)
}
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
index 7f53ee3731..56c6989d93 100644
--- a/src/cmd/compile/internal/x86/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -30,7 +30,6 @@ func Init(arch *gc.Arch) {
arch.MAXWIDTH = (1 << 32) - 1
arch.ZeroRange = zerorange
- arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
arch.Ginsnopdefer = ginsnop
diff --git a/src/cmd/compile/internal/x86/ggen.go b/src/cmd/compile/internal/x86/ggen.go
index f247180a2e..a33ddc81e3 100644
--- a/src/cmd/compile/internal/x86/ggen.go
+++ b/src/cmd/compile/internal/x86/ggen.go
@@ -37,22 +37,6 @@ func zerorange(pp *gc.Progs, p *obj.Prog, off, cnt int64, ax *uint32) *obj.Prog
return p
}
-func zeroAuto(pp *gc.Progs, n *gc.Node) {
- // Note: this code must not clobber any registers.
- sym := n.Sym.Linksym()
- size := n.Type.Size()
- for i := int64(0); i < size; i += 4 {
- p := pp.Prog(x86.AMOVL)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_AUTO
- p.To.Reg = x86.REG_SP
- p.To.Offset = n.Xoffset + i
- p.To.Sym = sym
- }
-}
-
func ginsnop(pp *gc.Progs) *obj.Prog {
// See comment in ../amd64/ggen.go.
p := pp.Prog(x86.AXCHGL)
--
cgit v1.3-5-g9baa
From 91f3997ec09d6502f88471f384aad2fe3ddcecb9 Mon Sep 17 00:00:00 2001
From: "Joshua M. Clulow"
Date: Mon, 28 Oct 2019 09:19:48 -0700
Subject: runtime: make NumCPU respect zone CPU cap on illumos
On illumos systems, check for the "zone.cpu-cap" resource control when
determining how many usable CPUs are available. If the resource control
is not set, or we are unable to read it, ignore the failure and return
the value we used to return; i.e., the CPU count from
sysconf(_SC_NPROCESSORS_ONLN).
Fixes golang/go#35199
Change-Id: Ic8a408f84cd140d544d128f1281baad527fb5e35
Reviewed-on: https://go-review.googlesource.com/c/go/+/203758
Run-TryBot: Brad Fitzpatrick
Reviewed-by: Brad Fitzpatrick
---
src/runtime/defs_illumos_amd64.go | 14 ++++
src/runtime/os3_solaris.go | 8 ---
src/runtime/os_illumos.go | 132 ++++++++++++++++++++++++++++++++++++++
src/runtime/os_only_solaris.go | 18 ++++++
4 files changed, 164 insertions(+), 8 deletions(-)
create mode 100644 src/runtime/defs_illumos_amd64.go
create mode 100644 src/runtime/os_illumos.go
create mode 100644 src/runtime/os_only_solaris.go
(limited to 'src')
diff --git a/src/runtime/defs_illumos_amd64.go b/src/runtime/defs_illumos_amd64.go
new file mode 100644
index 0000000000..9c5413bae3
--- /dev/null
+++ b/src/runtime/defs_illumos_amd64.go
@@ -0,0 +1,14 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+const (
+ _RCTL_LOCAL_DENY = 0x2
+
+ _RCTL_LOCAL_MAXIMAL = 0x80000000
+
+ _RCTL_FIRST = 0x0
+ _RCTL_NEXT = 0x1
+)
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 563e981d0f..373c682f05 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -119,14 +119,6 @@ var (
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
-func getncpu() int32 {
- n := int32(sysconf(__SC_NPROCESSORS_ONLN))
- if n < 1 {
- return 1
- }
- return n
-}
-
func getPageSize() uintptr {
n := int32(sysconf(__SC_PAGESIZE))
if n <= 0 {
diff --git a/src/runtime/os_illumos.go b/src/runtime/os_illumos.go
new file mode 100644
index 0000000000..c3c3e4e6d5
--- /dev/null
+++ b/src/runtime/os_illumos.go
@@ -0,0 +1,132 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+//go:cgo_import_dynamic libc_getrctl getrctl "libc.so"
+//go:cgo_import_dynamic libc_rctlblk_get_local_action rctlblk_get_local_action "libc.so"
+//go:cgo_import_dynamic libc_rctlblk_get_local_flags rctlblk_get_local_flags "libc.so"
+//go:cgo_import_dynamic libc_rctlblk_get_value rctlblk_get_value "libc.so"
+//go:cgo_import_dynamic libc_rctlblk_size rctlblk_size "libc.so"
+
+//go:linkname libc_getrctl libc_getrctl
+//go:linkname libc_rctlblk_get_local_action libc_rctlblk_get_local_action
+//go:linkname libc_rctlblk_get_local_flags libc_rctlblk_get_local_flags
+//go:linkname libc_rctlblk_get_value libc_rctlblk_get_value
+//go:linkname libc_rctlblk_size libc_rctlblk_size
+
+var (
+ libc_getrctl,
+ libc_rctlblk_get_local_action,
+ libc_rctlblk_get_local_flags,
+ libc_rctlblk_get_value,
+ libc_rctlblk_size libcFunc
+)
+
+// Return the minimum value seen for the zone CPU cap, or 0 if no cap is
+// detected.
+func getcpucap() uint64 {
+ // The resource control block is an opaque object whose size is only
+ // known to libc. In practice, given the contents, it is unlikely to
+ // grow beyond 8KB so we'll use a static buffer of that size here.
+ const rblkmaxsize = 8 * 1024
+ if rctlblk_size() > rblkmaxsize {
+ return 0
+ }
+
+ // The "zone.cpu-cap" resource control, as described in
+ // resource_controls(5), "sets a limit on the amount of CPU time that
+ // can be used by a zone. The unit used is the percentage of a single
+ // CPU that can be used by all user threads in a zone, expressed as an
+ // integer." A C string of the name must be passed to getrctl(2).
+ name := []byte("zone.cpu-cap\x00")
+
+ // To iterate over the list of values for a particular resource
+ // control, we need two blocks: one for the previously read value and
+ // one for the next value.
+ var rblk0 [rblkmaxsize]byte
+ var rblk1 [rblkmaxsize]byte
+ rblk := &rblk0[0]
+ rblkprev := &rblk1[0]
+
+ var flag uint32 = _RCTL_FIRST
+ var capval uint64 = 0
+
+ for {
+ if getrctl(unsafe.Pointer(&name[0]), unsafe.Pointer(rblkprev), unsafe.Pointer(rblk), flag) != 0 {
+ // The end of the sequence is reported as an ENOENT
+ // failure, but determining the CPU cap is not critical
+ // here. We'll treat any failure as if it were the end
+ // of sequence.
+ break
+ }
+
+ lflags := rctlblk_get_local_flags(unsafe.Pointer(rblk))
+ action := rctlblk_get_local_action(unsafe.Pointer(rblk))
+ if (lflags&_RCTL_LOCAL_MAXIMAL) == 0 && action == _RCTL_LOCAL_DENY {
+ // This is a finite (not maximal) value representing a
+ // cap (deny) action.
+ v := rctlblk_get_value(unsafe.Pointer(rblk))
+ if capval == 0 || capval > v {
+ capval = v
+ }
+ }
+
+ // Swap the blocks around so that we can fetch the next value
+ t := rblk
+ rblk = rblkprev
+ rblkprev = t
+ flag = _RCTL_NEXT
+ }
+
+ return capval
+}
+
+func getncpu() int32 {
+ n := int32(sysconf(__SC_NPROCESSORS_ONLN))
+ if n < 1 {
+ return 1
+ }
+
+ if cents := int32(getcpucap()); cents > 0 {
+ // Convert from a percentage of CPUs to a number of CPUs,
+ // rounding up to make use of a fractional CPU
+ // e.g., 336% becomes 4 CPUs
+ ncap := (cents + 99) / 100
+ if ncap < n {
+ return ncap
+ }
+ }
+
+ return n
+}
+
+//go:nosplit
+func getrctl(controlname, oldbuf, newbuf unsafe.Pointer, flags uint32) uintptr {
+ return sysvicall4(&libc_getrctl, uintptr(controlname), uintptr(oldbuf), uintptr(newbuf), uintptr(flags))
+}
+
+//go:nosplit
+func rctlblk_get_local_action(buf unsafe.Pointer) uintptr {
+ return sysvicall2(&libc_rctlblk_get_local_action, uintptr(buf), uintptr(0))
+}
+
+//go:nosplit
+func rctlblk_get_local_flags(buf unsafe.Pointer) uintptr {
+ return sysvicall1(&libc_rctlblk_get_local_flags, uintptr(buf))
+}
+
+//go:nosplit
+func rctlblk_get_value(buf unsafe.Pointer) uint64 {
+ return uint64(sysvicall1(&libc_rctlblk_get_value, uintptr(buf)))
+}
+
+//go:nosplit
+func rctlblk_size() uintptr {
+ return sysvicall0(&libc_rctlblk_size)
+}
diff --git a/src/runtime/os_only_solaris.go b/src/runtime/os_only_solaris.go
new file mode 100644
index 0000000000..e2f5409354
--- /dev/null
+++ b/src/runtime/os_only_solaris.go
@@ -0,0 +1,18 @@
+// Copyright 2019 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.
+
+// Solaris code that doesn't also apply to illumos.
+
+// +build !illumos
+
+package runtime
+
+func getncpu() int32 {
+ n := int32(sysconf(__SC_NPROCESSORS_ONLN))
+ if n < 1 {
+ return 1
+ }
+
+ return n
+}
--
cgit v1.3-5-g9baa
From 1c38ee5ffe223ebe1bc82404eddb111f5b5dbd8d Mon Sep 17 00:00:00 2001
From: Daniel Martí
Date: Sun, 27 Oct 2019 12:03:17 +0000
Subject: cmd: remove a few unused parameters
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
They all seem pretty low-risk, and the overall diff is small.
While at it, remove one in go/build too.
Change-Id: I31df52c1c97d843b06f6c1dc63462d390db4470d
Reviewed-on: https://go-review.googlesource.com/c/go/+/203607
Run-TryBot: Daniel Martí
TryBot-Result: Gobot Gobot
Reviewed-by: Bryan C. Mills
---
src/cmd/go/internal/envcmd/env.go | 6 +++---
src/cmd/go/internal/load/pkg.go | 7 +++----
src/cmd/go/internal/sumdb/server.go | 12 ++++++------
src/cmd/go/internal/work/buildid.go | 3 +--
src/cmd/go/internal/work/exec.go | 6 +++---
src/go/build/build.go | 7 ++++---
6 files changed, 20 insertions(+), 21 deletions(-)
(limited to 'src')
diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
index b80b181642..da704777f5 100644
--- a/src/cmd/go/internal/envcmd/env.go
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -237,7 +237,7 @@ func runEnv(cmd *base.Command, args []string) {
base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg)
}
key, val := arg[:i], arg[i+1:]
- if err := checkEnvWrite(key, val, env); err != nil {
+ if err := checkEnvWrite(key, val); err != nil {
base.Fatalf("go env -w: %v", err)
}
if _, ok := add[key]; ok {
@@ -259,7 +259,7 @@ func runEnv(cmd *base.Command, args []string) {
}
del := make(map[string]bool)
for _, arg := range args {
- if err := checkEnvWrite(arg, "", env); err != nil {
+ if err := checkEnvWrite(arg, ""); err != nil {
base.Fatalf("go env -u: %v", err)
}
del[arg] = true
@@ -330,7 +330,7 @@ func printEnvAsJSON(env []cfg.EnvVar) {
}
}
-func checkEnvWrite(key, val string, env []cfg.EnvVar) error {
+func checkEnvWrite(key, val string) error {
switch key {
case "GOEXE", "GOGCCFLAGS", "GOHOSTARCH", "GOHOSTOS", "GOMOD", "GOTOOLDIR":
return fmt.Errorf("%s cannot be modified", key)
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index 6b8ecc46b1..6a6f77e367 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -593,7 +593,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
return setErrorPos(perr, importPos)
}
if mode&ResolveImport != 0 {
- if perr := disallowVendor(srcDir, parent, parentPath, path, p, stk); perr != p {
+ if perr := disallowVendor(srcDir, path, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
}
@@ -1321,11 +1321,10 @@ func findInternal(path string) (index int, ok bool) {
return 0, false
}
-// disallowVendor checks that srcDir (containing package importerPath, if non-empty)
-// is allowed to import p as path.
+// disallowVendor checks that srcDir is allowed to import p as path.
// If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir string, importer *Package, importerPath, path string, p *Package, stk *ImportStack) *Package {
+func disallowVendor(srcDir string, path string, p *Package, stk *ImportStack) *Package {
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
diff --git a/src/cmd/go/internal/sumdb/server.go b/src/cmd/go/internal/sumdb/server.go
index 6370cf5fd5..16b04fce15 100644
--- a/src/cmd/go/internal/sumdb/server.go
+++ b/src/cmd/go/internal/sumdb/server.go
@@ -80,17 +80,17 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
escPath, escVers := mod[:i], mod[i+1:]
path, err := module.UnescapePath(escPath)
if err != nil {
- reportError(w, r, err)
+ reportError(w, err)
return
}
vers, err := module.UnescapeVersion(escVers)
if err != nil {
- reportError(w, r, err)
+ reportError(w, err)
return
}
id, err := s.ops.Lookup(ctx, module.Version{Path: path, Version: vers})
if err != nil {
- reportError(w, r, err)
+ reportError(w, err)
return
}
records, err := s.ops.ReadRecords(ctx, id, 1)
@@ -137,7 +137,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
start := t.N << uint(t.H)
records, err := s.ops.ReadRecords(ctx, start, int64(t.W))
if err != nil {
- reportError(w, r, err)
+ reportError(w, err)
return
}
if len(records) != t.W {
@@ -159,7 +159,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
data, err := s.ops.ReadTileData(ctx, t)
if err != nil {
- reportError(w, r, err)
+ reportError(w, err)
return
}
w.Header().Set("Content-Type", "application/octet-stream")
@@ -172,7 +172,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Otherwise it is an internal server error.
// The caller must only call reportError in contexts where
// a not-found err should be reported as 404.
-func reportError(w http.ResponseWriter, r *http.Request, err error) {
+func reportError(w http.ResponseWriter, err error) {
if os.IsNotExist(err) {
http.Error(w, err.Error(), http.StatusNotFound)
return
diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go
index 27bde8c615..7558a3091a 100644
--- a/src/cmd/go/internal/work/buildid.go
+++ b/src/cmd/go/internal/work/buildid.go
@@ -15,7 +15,6 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
- "cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/internal/buildid"
)
@@ -421,7 +420,7 @@ func (b *Builder) fileHash(file string) string {
// during a's work. The caller should defer b.flushOutput(a), to make sure
// that flushOutput is eventually called regardless of whether the action
// succeeds. The flushOutput call must happen after updateBuildID.
-func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID, target string) bool {
+func (b *Builder) useCache(a *Action, actionHash cache.ActionID, target string) bool {
// The second half of the build ID here is a placeholder for the content hash.
// It's important that the overall buildID be unlikely verging on impossible
// to appear in the output by chance, but that should be taken care of by
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 0f25a5d19f..a50de513f5 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -395,7 +395,7 @@ func (b *Builder) build(a *Action) (err error) {
bit(needCompiledGoFiles, b.NeedCompiledGoFiles)
if !p.BinaryOnly {
- if b.useCache(a, p, b.buildActionID(a), p.Target) {
+ if b.useCache(a, b.buildActionID(a), p.Target) {
// We found the main output in the cache.
// If we don't need any other outputs, we can stop.
// Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr).
@@ -1171,7 +1171,7 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {
// link is the action for linking a single command.
// Note that any new influence on this logic must be reported in b.linkActionID above as well.
func (b *Builder) link(a *Action) (err error) {
- if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) || b.IsCmdList {
+ if b.useCache(a, b.linkActionID(a), a.Package.Target) || b.IsCmdList {
return nil
}
defer b.flushOutput(a)
@@ -1404,7 +1404,7 @@ func (b *Builder) linkSharedActionID(a *Action) cache.ActionID {
}
func (b *Builder) linkShared(a *Action) (err error) {
- if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) || b.IsCmdList {
+ if b.useCache(a, b.linkSharedActionID(a), a.Target) || b.IsCmdList {
return nil
}
defer b.flushOutput(a)
diff --git a/src/go/build/build.go b/src/go/build/build.go
index c763db4f86..8832ab7856 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -592,13 +592,14 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
return p, fmt.Errorf("import %q: cannot import absolute path", path)
}
- gopath := ctxt.gopath() // needed by both importGo and below; avoid computing twice
- if err := ctxt.importGo(p, path, srcDir, mode, gopath); err == nil {
+ if err := ctxt.importGo(p, path, srcDir, mode); err == nil {
goto Found
} else if err != errNoModules {
return p, err
}
+ gopath := ctxt.gopath() // needed twice below; avoid computing many times
+
// tried records the location of unsuccessful package lookups
var tried struct {
vendor []string
@@ -990,7 +991,7 @@ var errNoModules = errors.New("not using modules")
// about the requested package and all dependencies and then only reports about the requested package.
// Then we reinvoke it for every dependency. But this is still better than not working at all.
// See golang.org/issue/26504.
-func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode, gopath []string) error {
+func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode) error {
const debugImportGo = false
// To invoke the go command, we must know the source directory,
--
cgit v1.3-5-g9baa
From 18e9cdc70e8da645302d96bab905e902f9cc776a Mon Sep 17 00:00:00 2001
From: Koichi Shiraishi
Date: Mon, 21 Oct 2019 15:48:23 +0900
Subject: cmd/link: use filepath.Clean rather than path.Clean
pname already translated package path into a file path on for statement.
Use same as filepath.Clean rather than path.Clean.
Change-Id: I9782e2396313abc39ac55e3fdcec8f53bcaff84e
Reviewed-on: https://go-review.googlesource.com/c/go/+/202377
Reviewed-by: Matthew Dempsky
---
src/cmd/link/internal/ld/ld.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
index d277220382..dae75a4c1a 100644
--- a/src/cmd/link/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -148,7 +148,7 @@ func findlib(ctxt *Link, lib string) (string, bool) {
}
}
}
- pname = path.Clean(pname)
+ pname = filepath.Clean(pname)
}
return pname, isshlib
--
cgit v1.3-5-g9baa
From e071cc4873d6b22c4ffe66f541bc65698b86afe2 Mon Sep 17 00:00:00 2001
From: Josh Bleecher Snyder
Date: Mon, 28 Oct 2019 08:32:06 -0700
Subject: cmd/compile: update comment about OpPhi argLength
We use -1 for Phi argLength, not "a really large number".
Change-Id: I5d4fa364c22c3cf40213f2368a9a20de7e989aac
Reviewed-on: https://go-review.googlesource.com/c/go/+/203883
Run-TryBot: Josh Bleecher Snyder
Reviewed-by: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/ssa/gen/genericOps.go | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index 7bd79312e3..748805f369 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -316,8 +316,7 @@ var genericOps = []opData{
// See section 7.2 in ieee754.
{name: "Fma", argLength: 3}, // compute (a*b)+c without intermediate rounding
- // Data movement, max argument length for Phi is indefinite so just pick
- // a really large number
+ // Data movement. Max argument length for Phi is indefinite.
{name: "Phi", argLength: -1, zeroWidth: true}, // select an argument based on which predecessor block we came from
{name: "Copy", argLength: 1}, // output = arg0
// Convert converts between pointers and integers.
--
cgit v1.3-5-g9baa
From 7131eb08ec72cc241f7db02bc647cf10098648a5 Mon Sep 17 00:00:00 2001
From: Josh Bleecher Snyder
Date: Mon, 28 Oct 2019 08:53:53 -0700
Subject: cmd: gofmt
Change-Id: I243b6521cb91ba5312c0857ca81cf422a7c7b21a
Reviewed-on: https://go-review.googlesource.com/c/go/+/203881
Run-TryBot: Josh Bleecher Snyder
Reviewed-by: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/cmd/compile/fmtmap_test.go | 66 +++++++++++++++---------------
src/cmd/compile/internal/ssa/branchelim.go | 2 +-
src/cmd/internal/src/pos.go | 2 +-
3 files changed, 35 insertions(+), 35 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/fmtmap_test.go b/src/cmd/compile/fmtmap_test.go
index ebbaf01b17..51b79c6a89 100644
--- a/src/cmd/compile/fmtmap_test.go
+++ b/src/cmd/compile/fmtmap_test.go
@@ -171,37 +171,37 @@ var knownFormats = map[string]string{
"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
"map[*cmd/compile/internal/gc.Node][]*cmd/compile/internal/gc.Node %v": "",
"map[cmd/compile/internal/ssa.ID]uint32 %v": "",
- "map[int64]uint32 %v": "",
- "math/big.Accuracy %s": "",
- "reflect.Type %s": "",
- "rune %#U": "",
- "rune %c": "",
- "rune %q": "",
- "string %-*s": "",
- "string %-16s": "",
- "string %-6s": "",
- "string %q": "",
- "string %s": "",
- "string %v": "",
- "time.Duration %d": "",
- "time.Duration %v": "",
- "uint %04x": "",
- "uint %5d": "",
- "uint %d": "",
- "uint %x": "",
- "uint16 %d": "",
- "uint16 %x": "",
- "uint32 %#U": "",
- "uint32 %#x": "",
- "uint32 %d": "",
- "uint32 %v": "",
- "uint32 %x": "",
- "uint64 %08x": "",
- "uint64 %b": "",
- "uint64 %d": "",
- "uint64 %x": "",
- "uint8 %d": "",
- "uint8 %v": "",
- "uint8 %x": "",
- "uintptr %d": "",
+ "map[int64]uint32 %v": "",
+ "math/big.Accuracy %s": "",
+ "reflect.Type %s": "",
+ "rune %#U": "",
+ "rune %c": "",
+ "rune %q": "",
+ "string %-*s": "",
+ "string %-16s": "",
+ "string %-6s": "",
+ "string %q": "",
+ "string %s": "",
+ "string %v": "",
+ "time.Duration %d": "",
+ "time.Duration %v": "",
+ "uint %04x": "",
+ "uint %5d": "",
+ "uint %d": "",
+ "uint %x": "",
+ "uint16 %d": "",
+ "uint16 %x": "",
+ "uint32 %#U": "",
+ "uint32 %#x": "",
+ "uint32 %d": "",
+ "uint32 %v": "",
+ "uint32 %x": "",
+ "uint64 %08x": "",
+ "uint64 %b": "",
+ "uint64 %d": "",
+ "uint64 %x": "",
+ "uint8 %d": "",
+ "uint8 %v": "",
+ "uint8 %x": "",
+ "uintptr %d": "",
}
diff --git a/src/cmd/compile/internal/ssa/branchelim.go b/src/cmd/compile/internal/ssa/branchelim.go
index 298eed362a..c7c3f8c15f 100644
--- a/src/cmd/compile/internal/ssa/branchelim.go
+++ b/src/cmd/compile/internal/ssa/branchelim.go
@@ -220,7 +220,7 @@ func elimIf(f *Func, loadAddr *sparseSet, dom *Block) bool {
// that has the same line number as the Pos for b itself, and
// puts a statement mark on it, and returns whether it succeeded
// in this operation.
- setBlockPos := func (b *Block) bool {
+ setBlockPos := func(b *Block) bool {
pos := b.Pos
for _, v := range b.Values {
if pos.SameFileAndLine(v.Pos) && !isPoorStatementOp(v.Op) {
diff --git a/src/cmd/internal/src/pos.go b/src/cmd/internal/src/pos.go
index 8c0b6d277b..60c7c91cde 100644
--- a/src/cmd/internal/src/pos.go
+++ b/src/cmd/internal/src/pos.go
@@ -382,7 +382,7 @@ func makeLico(line, col uint) lico {
}
func (x lico) Line() uint { return uint(x) >> lineShift }
-func (x lico) SameLine(y lico) bool { return 0 == (x^y)&^lico(1 << lineShift-1) }
+func (x lico) SameLine(y lico) bool { return 0 == (x^y)&^lico(1<> colShift & colMax }
func (x lico) IsStmt() uint {
if x == 0 {
--
cgit v1.3-5-g9baa
From 9be36ba7b46c71e9b58c71cfb75a890c3ed4e8a3 Mon Sep 17 00:00:00 2001
From: Josh Bleecher Snyder
Date: Mon, 28 Oct 2019 08:34:09 -0700
Subject: go.sum: add golang.org/x/tools sum
The go.mod sum was present, but not the module sum.
Change-Id: I7def303bf4507a88dfa1bb0502116efde4d64b01
Reviewed-on: https://go-review.googlesource.com/c/go/+/203882
Run-TryBot: Josh Bleecher Snyder
Reviewed-by: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/go.sum | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/go.sum b/src/go.sum
index 89a846d79d..7e882b8ca0 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -11,4 +11,5 @@ golang.org/x/sys v0.0.0-20190529130038-5219a1e1c5f8/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
--
cgit v1.3-5-g9baa
From 3e457030d9a0b9ed23d9d5b346723c54ccae1a8e Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Mon, 21 Oct 2019 17:01:14 -0700
Subject: go/parser, go/ast: correctly take into account presence of } in block
Correctly track whether the closing } of a block (or a function body)
is present or not in the AST and report correct End() positions in
each case.
There are more cases like this but this CL addresses an immediate
issue and sets a precedent for how to fix similar cases if a need
arises.
Fixes #33649.
Change-Id: Id6662ddaac09f3c15f8003edc9275fe2b0c41c78
Reviewed-on: https://go-review.googlesource.com/c/go/+/202581
Run-TryBot: Robert Griesemer
TryBot-Result: Gobot Gobot
Reviewed-by: Alan Donovan
---
src/go/ast/ast.go | 12 ++++++++++--
src/go/ast/issues_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++
src/go/parser/parser.go | 16 ++++++++++++++--
3 files changed, 66 insertions(+), 4 deletions(-)
create mode 100644 src/go/ast/issues_test.go
(limited to 'src')
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index d8f6f668cc..9e1da35287 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -634,7 +634,7 @@ type (
BlockStmt struct {
Lbrace token.Pos // position of "{"
List []Stmt
- Rbrace token.Pos // position of "}"
+ Rbrace token.Pos // position of "}", if any (may be absent due to syntax error)
}
// An IfStmt node represents an if statement.
@@ -757,7 +757,15 @@ func (s *BranchStmt) End() token.Pos {
}
return token.Pos(int(s.TokPos) + len(s.Tok.String()))
}
-func (s *BlockStmt) End() token.Pos { return s.Rbrace + 1 }
+func (s *BlockStmt) End() token.Pos {
+ if s.Rbrace.IsValid() {
+ return s.Rbrace + 1
+ }
+ if n := len(s.List); n > 0 {
+ return s.List[n-1].End()
+ }
+ return s.Lbrace + 1
+}
func (s *IfStmt) End() token.Pos {
if s.Else != nil {
return s.Else.End()
diff --git a/src/go/ast/issues_test.go b/src/go/ast/issues_test.go
new file mode 100644
index 0000000000..788c5578b8
--- /dev/null
+++ b/src/go/ast/issues_test.go
@@ -0,0 +1,42 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast_test
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "testing"
+)
+
+func TestIssue33649(t *testing.T) {
+ for _, src := range []string{
+ `package p; func _()`,
+ `package p; func _() {`,
+ `package p; func _() { _ = 0`,
+ `package p; func _() { _ = 0 }`,
+ } {
+ fset := token.NewFileSet()
+ f, _ := parser.ParseFile(fset, "", src, parser.AllErrors)
+ if f == nil {
+ panic("invalid test setup: parser didn't return an AST")
+ }
+
+ // find corresponding token.File
+ var tf *token.File
+ fset.Iterate(func(f *token.File) bool {
+ tf = f
+ return true
+ })
+ tfEnd := tf.Base() + tf.Size()
+
+ fd := f.Decls[len(f.Decls)-1].(*ast.FuncDecl)
+ fdEnd := int(fd.End())
+
+ if fdEnd != tfEnd {
+ t.Errorf("%q: got fdEnd = %d; want %d (base = %d, size = %d)", src, fdEnd, tfEnd, tf.Base(), tf.Size())
+ }
+ }
+}
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index 3a468d096b..beb563f25f 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -397,6 +397,18 @@ func (p *parser) expect(tok token.Token) token.Pos {
return pos
}
+// expect2 is like expect, but it returns an invalid position
+// if the expected token is not found.
+func (p *parser) expect2(tok token.Token) (pos token.Pos) {
+ if p.tok == tok {
+ pos = p.pos
+ } else {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress
+ return
+}
+
// expectClosing is like expect but provides a better error message
// for the common case of a missing comma before a newline.
//
@@ -1082,7 +1094,7 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
list := p.parseStmtList()
p.closeLabelScope()
p.closeScope()
- rbrace := p.expect(token.RBRACE)
+ rbrace := p.expect2(token.RBRACE)
return &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
}
@@ -1096,7 +1108,7 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
p.openScope()
list := p.parseStmtList()
p.closeScope()
- rbrace := p.expect(token.RBRACE)
+ rbrace := p.expect2(token.RBRACE)
return &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
}
--
cgit v1.3-5-g9baa
From 60f34f739de41d8000661baac5dc1cebba80e892 Mon Sep 17 00:00:00 2001
From: Jay Conrod
Date: Wed, 23 Oct 2019 17:14:09 -0400
Subject: cmd/dist: support GOROOT vendoring
In the second step of make.bash, cmd/dist builds cmd/go by invoking
the compiler, linker, and other tools directly on transitive
dependencies of cmd/go. Essentially, cmd/dist acts as a minimal
version of 'go install' when building go_toolchain.
Until now, cmd/go has had no transitive dependencies in vendor
directories. This changes in CL 202698, where several packages are
deleted and equivalent versions in golang.org/x/mod are used
instead. So this CL adds support to cmd/dist for vendor directories.
Updates #31761
Change-Id: Iab4cdc7e505069a8df296287d16fbaa871944955
Reviewed-on: https://go-review.googlesource.com/c/go/+/203537
Run-TryBot: Jay Conrod
TryBot-Result: Gobot Gobot
Reviewed-by: Bryan C. Mills
---
src/cmd/dist/build.go | 105 ++++++++++++++++++++++++++++++++----------------
src/cmd/dist/imports.go | 31 ++++++++++++++
2 files changed, 101 insertions(+), 35 deletions(-)
(limited to 'src')
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 8d29eb98a7..9eb9e8f241 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -605,26 +605,26 @@ func startInstall(dir string) chan struct{} {
// runInstall installs the library, package, or binary associated with dir,
// which is relative to $GOROOT/src.
-func runInstall(dir string, ch chan struct{}) {
- if dir == "net" || dir == "os/user" || dir == "crypto/x509" {
- fatalf("go_bootstrap cannot depend on cgo package %s", dir)
+func runInstall(pkg string, ch chan struct{}) {
+ if pkg == "net" || pkg == "os/user" || pkg == "crypto/x509" {
+ fatalf("go_bootstrap cannot depend on cgo package %s", pkg)
}
defer close(ch)
- if dir == "unsafe" {
+ if pkg == "unsafe" {
return
}
if vflag > 0 {
if goos != gohostos || goarch != gohostarch {
- errprintf("%s (%s/%s)\n", dir, goos, goarch)
+ errprintf("%s (%s/%s)\n", pkg, goos, goarch)
} else {
- errprintf("%s\n", dir)
+ errprintf("%s\n", pkg)
}
}
- workdir := pathf("%s/%s", workdir, dir)
+ workdir := pathf("%s/%s", workdir, pkg)
xmkdirall(workdir)
var clean []string
@@ -634,11 +634,14 @@ func runInstall(dir string, ch chan struct{}) {
}
}()
- // path = full path to dir.
- path := pathf("%s/src/%s", goroot, dir)
+ // dir = full path to pkg.
+ dir := pathf("%s/src/%s", goroot, pkg)
name := filepath.Base(dir)
- ispkg := !strings.HasPrefix(dir, "cmd/") || strings.Contains(dir, "/internal/")
+ // ispkg predicts whether the package should be linked as a binary, based
+ // on the name. There should be no "main" packages in vendor, since
+ // 'go mod vendor' will only copy imported packages there.
+ ispkg := !strings.HasPrefix(pkg, "cmd/") || strings.Contains(pkg, "/internal/") || strings.Contains(pkg, "/vendor/")
// Start final link command line.
// Note: code below knows that link.p[targ] is the target.
@@ -650,7 +653,7 @@ func runInstall(dir string, ch chan struct{}) {
if ispkg {
// Go library (package).
ispackcmd = true
- link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
+ link = []string{"pack", packagefile(pkg)}
targ = len(link) - 1
xmkdirall(filepath.Dir(link[targ]))
} else {
@@ -675,7 +678,7 @@ func runInstall(dir string, ch chan struct{}) {
// Gather files that are sources for this target.
// Everything in that directory, and any target-specific
// additions.
- files := xreaddir(path)
+ files := xreaddir(dir)
// Remove files beginning with . or _,
// which are likely to be editor temporary files.
@@ -687,7 +690,7 @@ func runInstall(dir string, ch chan struct{}) {
})
for _, dt := range deptab {
- if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
+ if pkg == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(pkg, dt.prefix) {
for _, p := range dt.dep {
p = os.ExpandEnv(p)
files = append(files, p)
@@ -699,7 +702,7 @@ func runInstall(dir string, ch chan struct{}) {
// Convert to absolute paths.
for i, p := range files {
if !filepath.IsAbs(p) {
- files[i] = pathf("%s/%s", path, p)
+ files[i] = pathf("%s/%s", dir, p)
}
}
@@ -715,7 +718,7 @@ func runInstall(dir string, ch chan struct{}) {
return false
ok:
t := mtime(p)
- if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
+ if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, pkg) {
return false
}
if strings.HasSuffix(p, ".go") {
@@ -742,7 +745,7 @@ func runInstall(dir string, ch chan struct{}) {
}
// For package runtime, copy some files into the work space.
- if dir == "runtime" {
+ if pkg == "runtime" {
xmkdirall(pathf("%s/pkg/include", goroot))
// For use by assembly and C files.
copyfile(pathf("%s/pkg/include/textflag.h", goroot),
@@ -764,7 +767,7 @@ func runInstall(dir string, ch chan struct{}) {
if vflag > 1 {
errprintf("generate %s\n", p)
}
- gt.gen(path, p)
+ gt.gen(dir, p)
// Do not add generated file to clean list.
// In runtime, we want to be able to
// build the package with the go tool,
@@ -782,22 +785,31 @@ func runInstall(dir string, ch chan struct{}) {
built:
}
- // Make sure dependencies are installed.
- var deps []string
+ // Resolve imported packages to actual package paths.
+ // Make sure they're installed.
+ importMap := make(map[string]string)
for _, p := range gofiles {
- deps = append(deps, readimports(p)...)
+ for _, imp := range readimports(p) {
+ importMap[imp] = resolveVendor(imp, dir)
+ }
+ }
+ sortedImports := make([]string, 0, len(importMap))
+ for imp := range importMap {
+ sortedImports = append(sortedImports, imp)
}
- for _, dir1 := range deps {
- startInstall(dir1)
+ sort.Strings(sortedImports)
+
+ for _, dep := range importMap {
+ startInstall(dep)
}
- for _, dir1 := range deps {
- install(dir1)
+ for _, dep := range importMap {
+ install(dep)
}
if goos != gohostos || goarch != gohostarch {
// We've generated the right files; the go command can do the build.
if vflag > 1 {
- errprintf("skip build for cross-compile %s\n", dir)
+ errprintf("skip build for cross-compile %s\n", pkg)
}
return
}
@@ -830,18 +842,35 @@ func runInstall(dir string, ch chan struct{}) {
if err := ioutil.WriteFile(goasmh, nil, 0666); err != nil {
fatalf("cannot write empty go_asm.h: %s", err)
}
- bgrun(&wg, path, asmabis...)
+ bgrun(&wg, dir, asmabis...)
bgwait(&wg)
}
+ // Build an importcfg file for the compiler.
+ buf := &bytes.Buffer{}
+ for _, imp := range sortedImports {
+ if imp == "unsafe" {
+ continue
+ }
+ dep := importMap[imp]
+ if imp != dep {
+ fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep)
+ }
+ fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep))
+ }
+ importcfg := pathf("%s/importcfg", workdir)
+ if err := ioutil.WriteFile(importcfg, buf.Bytes(), 0666); err != nil {
+ fatalf("cannot write importcfg file: %v", err)
+ }
+
var archive string
// The next loop will compile individual non-Go files.
// Hand the Go files to the compiler en masse.
// For packages containing assembly, this writes go_asm.h, which
// the assembly files will need.
- pkg := dir
- if strings.HasPrefix(dir, "cmd/") && strings.Count(dir, "/") == 1 {
- pkg = "main"
+ pkgName := pkg
+ if strings.HasPrefix(pkg, "cmd/") && strings.Count(pkg, "/") == 1 {
+ pkgName = "main"
}
b := pathf("%s/_go_.a", workdir)
clean = append(clean, b)
@@ -852,11 +881,11 @@ func runInstall(dir string, ch chan struct{}) {
}
// Compile Go code.
- compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkg}
+ compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkgName, "-importcfg", importcfg}
if gogcflags != "" {
compile = append(compile, strings.Fields(gogcflags)...)
}
- if dir == "runtime" {
+ if pkg == "runtime" {
compile = append(compile, "-+")
}
if len(sfiles) > 0 {
@@ -874,7 +903,7 @@ func runInstall(dir string, ch chan struct{}) {
// We use bgrun and immediately wait for it instead of calling run() synchronously.
// This executes all jobs through the bgwork channel and allows the process
// to exit cleanly in case an error occurs.
- bgrun(&wg, path, compile...)
+ bgrun(&wg, dir, compile...)
bgwait(&wg)
// Compile the files.
@@ -888,7 +917,7 @@ func runInstall(dir string, ch chan struct{}) {
// Change the last character of the output file (which was c or s).
b = b[:len(b)-1] + "o"
compile = append(compile, "-o", b, p)
- bgrun(&wg, path, compile...)
+ bgrun(&wg, dir, compile...)
link = append(link, b)
if doclean {
@@ -909,6 +938,12 @@ func runInstall(dir string, ch chan struct{}) {
bgwait(&wg)
}
+// packagefile returns the path to a compiled .a file for the given package
+// path. Paths may need to be resolved with resolveVendor first.
+func packagefile(pkg string) string {
+ return pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, pkg)
+}
+
// matchfield reports whether the field (x,y,z) matches this build.
// all the elements in the field must be satisfied.
func matchfield(f string) bool {
@@ -940,7 +975,7 @@ func matchtag(tag string) bool {
// of GOOS and GOARCH.
// We also allow the special tag cmd_go_bootstrap.
// See ../go/bootstrap.go and package go/build.
-func shouldbuild(file, dir string) bool {
+func shouldbuild(file, pkg string) bool {
// Check file name for GOOS or GOARCH.
name := filepath.Base(file)
excluded := func(list []string, ok string) bool {
@@ -982,7 +1017,7 @@ func shouldbuild(file, dir string) bool {
if code == "package documentation" {
return false
}
- if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
+ if code == "package main" && pkg != "cmd/go" && pkg != "cmd/cgo" {
return false
}
if !strings.HasPrefix(p, "//") {
diff --git a/src/cmd/dist/imports.go b/src/cmd/dist/imports.go
index bf64d6668a..05dd84d0f1 100644
--- a/src/cmd/dist/imports.go
+++ b/src/cmd/dist/imports.go
@@ -11,7 +11,10 @@ package main
import (
"bufio"
"errors"
+ "fmt"
"io"
+ "path"
+ "path/filepath"
"strconv"
"strings"
"unicode/utf8"
@@ -243,3 +246,31 @@ func readimports(file string) []string {
return imports
}
+
+// resolveVendor returns a unique package path imported with the given import
+// path from srcDir.
+//
+// resolveVendor assumes that a package is vendored if and only if its first
+// path component contains a dot. If a package is vendored, its import path
+// is returned with a "vendor" or "cmd/vendor" prefix, depending on srcDir.
+// Otherwise, the import path is returned verbatim.
+func resolveVendor(imp, srcDir string) string {
+ var first string
+ if i := strings.Index(imp, "/"); i < 0 {
+ first = imp
+ } else {
+ first = imp[:i]
+ }
+ isStandard := !strings.Contains(first, ".")
+ if isStandard {
+ return imp
+ }
+
+ if strings.HasPrefix(srcDir, filepath.Join(goroot, "src", "cmd")) {
+ return path.Join("cmd", "vendor", imp)
+ } else if strings.HasPrefix(srcDir, filepath.Join(goroot, "src")) {
+ return path.Join("vendor", imp)
+ } else {
+ panic(fmt.Sprintf("srcDir %q not in GOOROT/src", srcDir))
+ }
+}
--
cgit v1.3-5-g9baa
From 81d6ec204fcfbcbb617f38b8ee5183080669c066 Mon Sep 17 00:00:00 2001
From: Constantin Konstantinidis
Date: Sat, 26 Oct 2019 20:01:47 +0200
Subject: os: remove read-only directories in RemoveAll on Windows
Remove skipping of TestRemoveUnreadableDir on Windows.
Fixes #26295
Change-Id: I364a3caa55406c855ece807759f6298f7e4ddf1e
Reviewed-on: https://go-review.googlesource.com/c/go/+/203599
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/os/removeall_noat.go | 8 ++++++++
src/os/removeall_test.go | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/os/removeall_noat.go b/src/os/removeall_noat.go
index 32673c0ab0..953c4a2715 100644
--- a/src/os/removeall_noat.go
+++ b/src/os/removeall_noat.go
@@ -8,6 +8,7 @@ package os
import (
"io"
+ "runtime"
"syscall"
)
@@ -127,6 +128,13 @@ func removeAll(path string) error {
if err1 == nil || IsNotExist(err1) {
return nil
}
+ if runtime.GOOS == "windows" && IsPermission(err1) {
+ if fs, err := Stat(path); err == nil {
+ if err = Chmod(path, FileMode(0200 | int(fs.Mode()))); err == nil {
+ err1 = Remove(path)
+ }
+ }
+ }
if err == nil {
err = err1
}
diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go
index 1fa0dcdd33..0bf35751ce 100644
--- a/src/os/removeall_test.go
+++ b/src/os/removeall_test.go
@@ -378,7 +378,7 @@ func TestRemoveAllButReadOnlyAndPathError(t *testing.T) {
func TestRemoveUnreadableDir(t *testing.T) {
switch runtime.GOOS {
- case "js", "windows":
+ case "js":
t.Skipf("skipping test on %s", runtime.GOOS)
}
--
cgit v1.3-5-g9baa
From 59a684703913e383c482c1383b2d4958c674248c Mon Sep 17 00:00:00 2001
From: John Papandriopoulos
Date: Sun, 29 Sep 2019 16:59:56 -0700
Subject: cmd/link: pass-through undefined call targets in external link mode
Allows Go asm calls referencing a function in a .syso file to be
passed through to the external linker, that would have otherwise
raised a "relocation target X not defined" error in cmd/link.
Fixes #33139
Change-Id: I2a8eb6063ebcd05fac96f141acf7652cf9189766
Reviewed-on: https://go-review.googlesource.com/c/go/+/198798
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
.../go/testdata/script/link_syso_issue33139.txt | 43 ++++++++++++++++++++++
src/cmd/link/internal/arm/asm.go | 2 +-
src/cmd/link/internal/ld/data.go | 15 +++++++-
src/cmd/link/internal/ld/go.go | 18 +++++++++
src/cmd/link/internal/ld/lib.go | 5 +++
src/cmd/link/internal/ld/macho.go | 4 +-
src/cmd/link/internal/ld/pe.go | 2 +-
src/cmd/link/internal/ld/symtab.go | 2 +-
src/cmd/link/internal/ld/xcoff.go | 2 +-
src/cmd/link/internal/ppc64/asm.go | 2 +-
src/cmd/link/internal/sym/symkind.go | 1 +
src/cmd/link/internal/sym/symkind_string.go | 19 +++++-----
12 files changed, 97 insertions(+), 18 deletions(-)
create mode 100644 src/cmd/go/testdata/script/link_syso_issue33139.txt
(limited to 'src')
diff --git a/src/cmd/go/testdata/script/link_syso_issue33139.txt b/src/cmd/go/testdata/script/link_syso_issue33139.txt
new file mode 100644
index 0000000000..c2ca27acbf
--- /dev/null
+++ b/src/cmd/go/testdata/script/link_syso_issue33139.txt
@@ -0,0 +1,43 @@
+# Test that we can use the external linker with a host syso file that is
+# embedded in a package, that is referenced by a Go assembly function.
+# See issue 33139.
+[!gc] skip
+[!exec:cc] skip
+
+# External linking is not supported on linux/ppc64.
+# See: https://github.com/golang/go/issues/8912
+[linux] [ppc64] skip
+
+# External linking is not supported on darwin/386 (10.14+).
+# See: https://github.com/golang/go/issues/31751
+[darwin] [386] skip
+
+cc -c -o syso/objTestImpl.syso syso/src/objTestImpl.c
+go build -ldflags='-linkmode=external' ./cmd/main.go
+
+-- syso/objTest.s --
+#include "textflag.h"
+
+TEXT ·ObjTest(SB), NOSPLIT, $0
+ // We do not actually execute this function in the test above, thus
+ // there is no stack frame setup here.
+ // We only care about Go build and/or link errors when referencing
+ // the objTestImpl symbol in the syso file.
+ JMP objTestImpl(SB)
+
+-- syso/pkg.go --
+package syso
+
+func ObjTest()
+
+-- syso/src/objTestImpl.c --
+void objTestImpl() { /* Empty */ }
+
+-- cmd/main.go --
+package main
+
+import "syso"
+
+func main() {
+ syso.ObjTest()
+}
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index 995a703dd4..f2fb6543d0 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -613,7 +613,7 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
rs = rs.Outer
}
- if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
+ if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
ld.Errorf(s, "missing section for %s", rs.Name)
}
r.Xsym = rs
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 4da5ce3f70..89485b8be4 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -96,7 +96,7 @@ func trampoline(ctxt *Link, s *sym.Symbol) {
if !r.Type.IsDirectJump() {
continue
}
- if Symaddr(r.Sym) == 0 && r.Sym.Type != sym.SDYNIMPORT {
+ if Symaddr(r.Sym) == 0 && (r.Sym.Type != sym.SDYNIMPORT && r.Sym.Type != sym.SUNDEFEXT) {
if r.Sym.File != s.File {
if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) {
ctxt.ErrorUnresolved(s, r)
@@ -298,7 +298,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
rs = rs.Outer
}
- if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
+ if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
Errorf(s, "missing section for relocation target %s", rs.Name)
}
r.Xsym = rs
@@ -418,6 +418,17 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
}
fallthrough
case objabi.R_CALL, objabi.R_PCREL:
+ if ctxt.LinkMode == LinkExternal && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
+ // pass through to the external linker.
+ r.Done = false
+ r.Xadd = 0
+ if ctxt.IsELF {
+ r.Xadd -= int64(r.Siz)
+ }
+ r.Xsym = r.Sym
+ o = 0
+ break
+ }
if ctxt.LinkMode == LinkExternal && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
r.Done = false
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index 80d7ac32f5..37adeb7701 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -334,6 +334,24 @@ func fieldtrack(ctxt *Link) {
}
func (ctxt *Link) addexport() {
+ // Track undefined external symbols during external link.
+ if ctxt.LinkMode == LinkExternal {
+ for _, s := range ctxt.Syms.Allsym {
+ if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() {
+ continue
+ }
+ if s.Type != sym.STEXT {
+ continue
+ }
+ for i := range s.R {
+ r := &s.R[i]
+ if r.Sym != nil && r.Sym.Type == sym.Sxxx {
+ r.Sym.Type = sym.SUNDEFEXT
+ }
+ }
+ }
+ }
+
// TODO(aix)
if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
return
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index a6fa14cc74..308d506fc3 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -2369,6 +2369,11 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
}
put(ctxt, s, s.Name, BSSSym, Symaddr(s), s.Gotype)
+ case sym.SUNDEFEXT:
+ if ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Haix || ctxt.IsELF {
+ put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
+ }
+
case sym.SHOSTOBJ:
if ctxt.HeadType == objabi.Hwindows || ctxt.IsELF {
put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index 7453f37c62..e9e48768c1 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -809,7 +809,7 @@ func machogenasmsym(ctxt *Link) {
}
}
- if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ {
+ if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ || s.Type == sym.SUNDEFEXT {
if s.Attr.Reachable() {
addsym(ctxt, s, "", DataSym, 0, nil)
}
@@ -886,7 +886,7 @@ func machosymtab(ctxt *Link) {
// replace "·" as ".", because DTrace cannot handle it.
Addstring(symstr, strings.Replace(s.Extname(), "·", ".", -1))
- if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ {
+ if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ || s.Type == sym.SUNDEFEXT {
symtab.AddUint8(0x01) // type N_EXT, external symbol
symtab.AddUint8(0) // no section
symtab.AddUint16(ctxt.Arch, 0) // desc
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index b5851a94a0..4ab346e733 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -685,7 +685,7 @@ func (f *peFile) writeSymbols(ctxt *Link) {
// Only windows/386 requires underscore prefix on external symbols.
if ctxt.Arch.Family == sys.I386 &&
ctxt.LinkMode == LinkExternal &&
- (s.Type == sym.SHOSTOBJ || s.Attr.CgoExport()) {
+ (s.Type == sym.SHOSTOBJ || s.Type == sym.SUNDEFEXT || s.Attr.CgoExport()) {
s.Name = "_" + s.Name
}
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index b4236a5239..9ed5db0557 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -110,7 +110,7 @@ func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go
}
var elfshnum int
- if xo.Type == sym.SDYNIMPORT || xo.Type == sym.SHOSTOBJ {
+ if xo.Type == sym.SDYNIMPORT || xo.Type == sym.SHOSTOBJ || xo.Type == sym.SUNDEFEXT {
elfshnum = SHN_UNDEF
} else {
if xo.Sect == nil {
diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go
index c64066acec..fe35578225 100644
--- a/src/cmd/link/internal/ld/xcoff.go
+++ b/src/cmd/link/internal/ld/xcoff.go
@@ -955,7 +955,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
syms = append(syms, a4)
case UndefinedSym:
- if x.Type != sym.SDYNIMPORT && x.Type != sym.SHOSTOBJ {
+ if x.Type != sym.SDYNIMPORT && x.Type != sym.SHOSTOBJ && x.Type != sym.SUNDEFEXT {
return
}
s := &XcoffSymEnt64{
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index fadff89a46..45731c0638 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -801,7 +801,7 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
rs = rs.Outer
}
- if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
+ if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil {
ld.Errorf(s, "missing section for %s", rs.Name)
}
r.Xsym = rs
diff --git a/src/cmd/link/internal/sym/symkind.go b/src/cmd/link/internal/sym/symkind.go
index 4e44d3fce1..5309e07ecf 100644
--- a/src/cmd/link/internal/sym/symkind.go
+++ b/src/cmd/link/internal/sym/symkind.go
@@ -104,6 +104,7 @@ const (
SCONST
SDYNIMPORT
SHOSTOBJ
+ SUNDEFEXT // Undefined symbol for resolution by external linker
// Sections for debugging information
SDWARFSECT
diff --git a/src/cmd/link/internal/sym/symkind_string.go b/src/cmd/link/internal/sym/symkind_string.go
index 2732ec7654..e48d90c511 100644
--- a/src/cmd/link/internal/sym/symkind_string.go
+++ b/src/cmd/link/internal/sym/symkind_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=SymKind"; DO NOT EDIT.
+// Code generated by "stringer -type=SymKind symkind.go"; DO NOT EDIT.
package sym
@@ -54,17 +54,18 @@ func _() {
_ = x[SCONST-43]
_ = x[SDYNIMPORT-44]
_ = x[SHOSTOBJ-45]
- _ = x[SDWARFSECT-46]
- _ = x[SDWARFINFO-47]
- _ = x[SDWARFRANGE-48]
- _ = x[SDWARFLOC-49]
- _ = x[SDWARFLINES-50]
- _ = x[SABIALIAS-51]
+ _ = x[SUNDEFEXT-46]
+ _ = x[SDWARFSECT-47]
+ _ = x[SDWARFINFO-48]
+ _ = x[SDWARFRANGE-49]
+ _ = x[SDWARFLOC-50]
+ _ = x[SDWARFLINES-51]
+ _ = x[SABIALIAS-52]
}
-const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSFirstWritableSBUILDINFOSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASXCOFFTOCSBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOCSDWARFLINESSABIALIAS"
+const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSFirstWritableSBUILDINFOSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASXCOFFTOCSBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSCONSTSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOCSDWARFLINESSABIALIAS"
-var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 220, 230, 238, 244, 253, 261, 268, 278, 286, 291, 300, 304, 313, 320, 325, 337, 349, 366, 383, 392, 398, 408, 416, 426, 436, 447, 456, 467, 476}
+var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 220, 230, 238, 244, 253, 261, 268, 278, 286, 291, 300, 304, 313, 320, 325, 337, 349, 366, 383, 392, 398, 408, 416, 425, 435, 445, 456, 465, 476, 485}
func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) {
--
cgit v1.3-5-g9baa
From bf670bd83c849b56426c63b49f28121210a627ca Mon Sep 17 00:00:00 2001
From: Agniva De Sarker
Date: Wed, 13 Feb 2019 08:49:52 +0530
Subject: go/ast: fix SortImports to handle block comments (take 2)
This is a 2nd attempt at fixing CL 162337 which had an off-by-one error.
We were unconditionally getting the position of the start of the next line
from the last import without checking whether it is the end of the file or not.
Fix the code to check for that and move the testcase added in CL 190523
to the end of the file for it to trigger the issue properly.
Fixes #18929
Change-Id: I59e77256e256570b160fea6a17bce9ef49e810df
Reviewed-on: https://go-review.googlesource.com/c/go/+/190480
Run-TryBot: Agniva De Sarker
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
---
src/cmd/gofmt/testdata/import.golden | 73 ++++++++++++++++++++++++++++--
src/cmd/gofmt/testdata/import.input | 71 +++++++++++++++++++++++++++--
src/go/ast/import.go | 88 ++++++++++++++++++++++++++----------
3 files changed, 201 insertions(+), 31 deletions(-)
(limited to 'src')
diff --git a/src/cmd/gofmt/testdata/import.golden b/src/cmd/gofmt/testdata/import.golden
index 29bdc9baf4..1125b70cb7 100644
--- a/src/cmd/gofmt/testdata/import.golden
+++ b/src/cmd/gofmt/testdata/import.golden
@@ -1,3 +1,4 @@
+// package comment
package main
import (
@@ -8,11 +9,6 @@ import (
"math"
)
-import (
- "fmt"
- "math"
-)
-
import (
"fmt"
@@ -25,6 +21,10 @@ import (
"io"
)
+// We reset the line numbering to test that
+// the formatting works independent of line directives
+//line :19
+
import (
"errors"
"fmt"
@@ -129,3 +129,66 @@ import (
"dedup_by_group"
)
+
+import (
+ "fmt" // for Printf
+ /* comment */ io1 "io"
+ /* comment */ io2 "io"
+ /* comment */ "log"
+)
+
+import (
+ "fmt"
+ /* comment */ io1 "io"
+ /* comment */ io2 "io" // hello
+ "math" /* right side */
+ // end
+)
+
+import (
+ "errors" // for New
+ "fmt"
+ /* comment */ io1 "io" /* before */ // after
+ io2 "io" // another
+ // end
+)
+
+import (
+ "errors" // for New
+ /* left */ "fmt" /* right */
+ "log" // for Fatal
+ /* left */ "math" /* right */
+)
+
+import /* why */ /* comment here? */ (
+ /* comment */ "fmt"
+ "math"
+)
+
+// Reset it again
+//line :100
+
+// Dedup with different import styles
+import (
+ "path"
+ . "path"
+ _ "path"
+ pathpkg "path"
+)
+
+/* comment */
+import (
+ "fmt"
+ "math" // for Abs
+ // This is a new run
+ "errors"
+ "fmt"
+)
+
+// End an import declaration in the same line
+// as the last import. See golang.org/issue/33538.
+// Note: Must be the last (or 2nd last) line of the file.
+import (
+ "fmt"
+ "math"
+)
diff --git a/src/cmd/gofmt/testdata/import.input b/src/cmd/gofmt/testdata/import.input
index 78ab4f6544..040b8722d4 100644
--- a/src/cmd/gofmt/testdata/import.input
+++ b/src/cmd/gofmt/testdata/import.input
@@ -1,3 +1,4 @@
+// package comment
package main
import (
@@ -8,9 +9,6 @@ import (
"io"
)
-import("fmt"
-"math")
-
import (
"fmt"
@@ -23,6 +21,10 @@ import (
"io"
)
+// We reset the line numbering to test that
+// the formatting works independent of line directives
+//line :19
+
import (
"fmt"
"math"
@@ -132,3 +134,66 @@ import (
"dedup_by_group"
)
+
+import (
+ /* comment */ io1 "io"
+ "fmt" // for Printf
+ /* comment */ "log"
+ /* comment */ io2 "io"
+)
+
+import (
+ /* comment */ io2 "io" // hello
+ /* comment */ io1 "io"
+ "math" /* right side */
+ "fmt"
+ // end
+)
+
+import (
+ /* comment */ io1 "io" /* before */ // after
+ "fmt"
+ "errors" // for New
+ io2 "io" // another
+ // end
+)
+
+import (
+ /* left */ "fmt" /* right */
+ "errors" // for New
+ /* left */ "math" /* right */
+ "log" // for Fatal
+)
+
+import /* why */ /* comment here? */ (
+ /* comment */ "fmt"
+ "math"
+)
+
+// Reset it again
+//line :100
+
+// Dedup with different import styles
+import (
+ "path"
+ . "path"
+ _ "path"
+ "path"
+ pathpkg "path"
+)
+
+/* comment */
+import (
+ "math" // for Abs
+ "fmt"
+ // This is a new run
+ "errors"
+ "fmt"
+ "errors"
+)
+
+// End an import declaration in the same line
+// as the last import. See golang.org/issue/33538.
+// Note: Must be the last (or 2nd last) line of the file.
+import("fmt"
+"math")
\ No newline at end of file
diff --git a/src/go/ast/import.go b/src/go/ast/import.go
index be23c7fc43..7fdf137d14 100644
--- a/src/go/ast/import.go
+++ b/src/go/ast/import.go
@@ -30,7 +30,7 @@ func SortImports(fset *token.FileSet, f *File) {
i := 0
specs := d.Specs[:0]
for j, s := range d.Specs {
- if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line {
+ if j > i && lineAt(fset, s.Pos()) > 1+lineAt(fset, d.Specs[j-1].End()) {
// j begins a new run. End this one.
specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...)
i = j
@@ -42,8 +42,8 @@ func SortImports(fset *token.FileSet, f *File) {
// Deduping can leave a blank line before the rparen; clean that up.
if len(d.Specs) > 0 {
lastSpec := d.Specs[len(d.Specs)-1]
- lastLine := fset.Position(lastSpec.Pos()).Line
- rParenLine := fset.Position(d.Rparen).Line
+ lastLine := lineAt(fset, lastSpec.Pos())
+ rParenLine := lineAt(fset, d.Rparen)
for rParenLine > lastLine+1 {
rParenLine--
fset.File(d.Rparen).MergeLine(rParenLine)
@@ -52,6 +52,10 @@ func SortImports(fset *token.FileSet, f *File) {
}
}
+func lineAt(fset *token.FileSet, pos token.Pos) int {
+ return fset.PositionFor(pos, false).Line
+}
+
func importPath(s Spec) string {
t, err := strconv.Unquote(s.(*ImportSpec).Path.Value)
if err == nil {
@@ -89,6 +93,11 @@ type posSpan struct {
End token.Pos
}
+type cgPos struct {
+ left bool // true if comment is to the left of the spec, false otherwise.
+ cg *CommentGroup
+}
+
func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
// Can't short-circuit here even if specs are already sorted,
// since they might yet need deduplication.
@@ -104,39 +113,64 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
}
// Identify comments in this range.
- // Any comment from pos[0].Start to the final line counts.
- lastLine := fset.Position(pos[len(pos)-1].End).Line
- cstart := len(f.Comments)
- cend := len(f.Comments)
+ begSpecs := pos[0].Start
+ endSpecs := pos[len(pos)-1].End
+ beg := fset.File(begSpecs).LineStart(lineAt(fset, begSpecs))
+ endLine := lineAt(fset, endSpecs)
+ endFile := fset.File(endSpecs)
+ var end token.Pos
+ if endLine == endFile.LineCount() {
+ end = endSpecs
+ } else {
+ end = endFile.LineStart(endLine + 1) // beginning of next line
+ }
+ first := len(f.Comments)
+ last := -1
for i, g := range f.Comments {
- if g.Pos() < pos[0].Start {
- continue
- }
- if i < cstart {
- cstart = i
- }
- if fset.Position(g.End()).Line > lastLine {
- cend = i
+ if g.End() >= end {
break
}
+ // g.End() < end
+ if beg <= g.Pos() {
+ // comment is within the range [beg, end[ of import declarations
+ if i < first {
+ first = i
+ }
+ if i > last {
+ last = i
+ }
+ }
}
- comments := f.Comments[cstart:cend]
- // Assign each comment to the import spec preceding it.
- importComments := map[*ImportSpec][]*CommentGroup{}
+ var comments []*CommentGroup
+ if last >= 0 {
+ comments = f.Comments[first : last+1]
+ }
+
+ // Assign each comment to the import spec on the same line.
+ importComments := map[*ImportSpec][]cgPos{}
specIndex := 0
for _, g := range comments {
for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() {
specIndex++
}
+ var left bool
+ // A block comment can appear before the first import spec.
+ if specIndex == 0 && pos[specIndex].Start > g.Pos() {
+ left = true
+ } else if specIndex+1 < len(specs) && // Or it can appear on the left of an import spec.
+ lineAt(fset, pos[specIndex].Start)+1 == lineAt(fset, g.Pos()) {
+ specIndex++
+ left = true
+ }
s := specs[specIndex].(*ImportSpec)
- importComments[s] = append(importComments[s], g)
+ importComments[s] = append(importComments[s], cgPos{left: left, cg: g})
}
// Sort the import specs by import path.
// Remove duplicates, when possible without data loss.
// Reassign the import paths to have the same position sequence.
- // Reassign each comment to abut the end of its spec.
+ // Reassign each comment to the spec on the same line.
// Sort the comments by new position.
sort.Slice(specs, func(i, j int) bool {
ipath := importPath(specs[i])
@@ -160,7 +194,7 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
deduped = append(deduped, s)
} else {
p := s.Pos()
- fset.File(p).MergeLine(fset.Position(p).Line)
+ fset.File(p).MergeLine(lineAt(fset, p))
}
}
specs = deduped
@@ -174,8 +208,16 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
s.Path.ValuePos = pos[i].Start
s.EndPos = pos[i].End
for _, g := range importComments[s] {
- for _, c := range g.List {
- c.Slash = pos[i].End
+ for _, c := range g.cg.List {
+ if g.left {
+ c.Slash = pos[i].Start - 1
+ } else {
+ // An import spec can have both block comment and a line comment
+ // to its right. In that case, both of them will have the same pos.
+ // But while formatting the AST, the line comment gets moved to
+ // after the block comment.
+ c.Slash = pos[i].End
+ }
}
}
}
--
cgit v1.3-5-g9baa
From 449b6abbacc464443a7faf166bf4db3df3e0f8da Mon Sep 17 00:00:00 2001
From: Shenghou Ma
Date: Thu, 24 Oct 2019 21:29:30 -0400
Subject: cmd/compile/internal/gc: reword "declared and not used" error message
"declared and not used" is technically correct, but might confuse
the user. Switching "and" to "but" will hopefully create the
contrast for the users: they did one thing (declaration), but
not the other --- actually using the variable.
This new message is still not ideal (specifically, declared is not
entirely precise here), but at least it matches the other parsers
and is one step in the right direction.
Change-Id: I725c7c663535f9ab9725c4b0bf35b4fa74b0eb20
Reviewed-on: https://go-review.googlesource.com/c/go/+/203282
Run-TryBot: Minux Ma
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
Reviewed-by: Matthew Dempsky
---
src/cmd/compile/internal/gc/swt.go | 2 +-
src/cmd/compile/internal/gc/walk.go | 4 ++--
test/fixedbugs/bug373.go | 2 +-
test/fixedbugs/issue21317.go | 4 ++--
test/fixedbugs/issue23116.go | 2 +-
test/fixedbugs/issue29870b.go | 2 +-
test/typeswitch2b.go | 4 ++--
7 files changed, 10 insertions(+), 10 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 2970993056..0d5df2e0bd 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -32,7 +32,7 @@ func typecheckTypeSwitch(n *Node) {
// declaration itself. So if there are no cases, we won't
// notice that it went unused.
if v := n.Left.Left; v != nil && !v.isBlank() && n.List.Len() == 0 {
- yyerrorl(v.Pos, "%v declared and not used", v.Sym)
+ yyerrorl(v.Pos, "%v declared but not used", v.Sym)
}
var defCase, nilCase *Node
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 7d9f0cbd58..0e780bad6c 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -50,10 +50,10 @@ func walk(fn *Node) {
if defn.Left.Name.Used() {
continue
}
- yyerrorl(defn.Left.Pos, "%v declared and not used", ln.Sym)
+ yyerrorl(defn.Left.Pos, "%v declared but not used", ln.Sym)
defn.Left.Name.SetUsed(true) // suppress repeats
} else {
- yyerrorl(ln.Pos, "%v declared and not used", ln.Sym)
+ yyerrorl(ln.Pos, "%v declared but not used", ln.Sym)
}
}
diff --git a/test/fixedbugs/bug373.go b/test/fixedbugs/bug373.go
index aa0f5d1efa..6b7a312097 100644
--- a/test/fixedbugs/bug373.go
+++ b/test/fixedbugs/bug373.go
@@ -9,7 +9,7 @@
package foo
func f(x interface{}) {
- switch t := x.(type) { // ERROR "declared and not used"
+ switch t := x.(type) { // ERROR "declared but not used"
case int:
}
}
diff --git a/test/fixedbugs/issue21317.go b/test/fixedbugs/issue21317.go
index 530694af12..ee1bbf810b 100644
--- a/test/fixedbugs/issue21317.go
+++ b/test/fixedbugs/issue21317.go
@@ -48,8 +48,8 @@ func main() {
log.Fatalf("expected cmd/compile to fail")
}
wantErrs := []string{
- "7:9: n declared and not used",
- "7:12: err declared and not used",
+ "7:9: n declared but not used",
+ "7:12: err declared but not used",
}
outStr := string(out)
for _, want := range wantErrs {
diff --git a/test/fixedbugs/issue23116.go b/test/fixedbugs/issue23116.go
index 1737fee2c8..b4b36d4ba9 100644
--- a/test/fixedbugs/issue23116.go
+++ b/test/fixedbugs/issue23116.go
@@ -10,6 +10,6 @@ func f(x interface{}) {
switch x.(type) {
}
- switch t := x.(type) { // ERROR "declared and not used"
+ switch t := x.(type) { // ERROR "declared but not used"
}
}
diff --git a/test/fixedbugs/issue29870b.go b/test/fixedbugs/issue29870b.go
index 1bac566bbb..2d5f638530 100644
--- a/test/fixedbugs/issue29870b.go
+++ b/test/fixedbugs/issue29870b.go
@@ -10,5 +10,5 @@
package main
func _() {
- x := 7 // ERROR "x declared and not used"
+ x := 7 // ERROR "x declared but not used"
}
diff --git a/test/typeswitch2b.go b/test/typeswitch2b.go
index 135ae86cff..6da0d5fa6e 100644
--- a/test/typeswitch2b.go
+++ b/test/typeswitch2b.go
@@ -11,9 +11,9 @@ package main
func notused(x interface{}) {
// The first t is in a different scope than the 2nd t; it cannot
- // be accessed (=> declared and not used error); but it is legal
+ // be accessed (=> declared but not used error); but it is legal
// to declare it.
- switch t := 0; t := x.(type) { // ERROR "declared and not used"
+ switch t := 0; t := x.(type) { // ERROR "declared but not used"
case int:
_ = t // this is using the t of "t := x.(type)"
}
--
cgit v1.3-5-g9baa
From fd1e60f6e3bd42075e335a90ad36719ffed0eb1a Mon Sep 17 00:00:00 2001
From: Mikhail Fesenko
Date: Mon, 28 Oct 2019 21:51:00 +0000
Subject: cmd/fix, cmd/go, cmd/gofmt: refactor common code into new internal
diff package
Change-Id: Idac8473d1752059bf2f617fd7a781000ee2c3af4
GitHub-Last-Rev: 02a3aa1a3241d3ed4422518f1c954cd54bbe858e
GitHub-Pull-Request: golang/go#35141
Reviewed-on: https://go-review.googlesource.com/c/go/+/203218
Run-TryBot: Ian Lance Taylor
Reviewed-by: Ian Lance Taylor
---
src/cmd/fix/main.go | 49 ++-------------------------
src/cmd/fix/main_test.go | 4 ++-
src/cmd/go/internal/modfile/read_test.go | 33 ++----------------
src/cmd/gofmt/gofmt.go | 46 ++++---------------------
src/cmd/gofmt/gofmt_test.go | 4 +--
src/cmd/internal/diff/diff.go | 58 ++++++++++++++++++++++++++++++++
6 files changed, 75 insertions(+), 119 deletions(-)
create mode 100644 src/cmd/internal/diff/diff.go
(limited to 'src')
diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go
index f54a5e0d96..80b3c76350 100644
--- a/src/cmd/fix/main.go
+++ b/src/cmd/fix/main.go
@@ -15,11 +15,11 @@ import (
"go/token"
"io/ioutil"
"os"
- "os/exec"
"path/filepath"
- "runtime"
"sort"
"strings"
+
+ "cmd/internal/diff"
)
var (
@@ -186,7 +186,7 @@ func processFile(filename string, useStdin bool) error {
}
if *doDiff {
- data, err := diff(src, newSrc)
+ data, err := diff.Diff("go-fix", src, newSrc)
if err != nil {
return fmt.Errorf("computing diff: %s", err)
}
@@ -237,46 +237,3 @@ func isGoFile(f os.FileInfo) bool {
name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}
-
-func writeTempFile(dir, prefix string, data []byte) (string, error) {
- file, err := ioutil.TempFile(dir, prefix)
- if err != nil {
- return "", err
- }
- _, err = file.Write(data)
- if err1 := file.Close(); err == nil {
- err = err1
- }
- if err != nil {
- os.Remove(file.Name())
- return "", err
- }
- return file.Name(), nil
-}
-
-func diff(b1, b2 []byte) (data []byte, err error) {
- f1, err := writeTempFile("", "go-fix", b1)
- if err != nil {
- return
- }
- defer os.Remove(f1)
-
- f2, err := writeTempFile("", "go-fix", b2)
- if err != nil {
- return
- }
- defer os.Remove(f2)
-
- cmd := "diff"
- if runtime.GOOS == "plan9" {
- cmd = "/bin/ape/diff"
- }
-
- data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput()
- if len(data) > 0 {
- // diff exits with a non-zero status when the files don't match.
- // Ignore that failure as long as we get output.
- err = nil
- }
- return
-}
diff --git a/src/cmd/fix/main_test.go b/src/cmd/fix/main_test.go
index 8868140ade..ee74f24c6e 100644
--- a/src/cmd/fix/main_test.go
+++ b/src/cmd/fix/main_test.go
@@ -9,6 +9,8 @@ import (
"go/parser"
"strings"
"testing"
+
+ "cmd/internal/diff"
)
type testCase struct {
@@ -123,7 +125,7 @@ func TestRewrite(t *testing.T) {
}
func tdiff(t *testing.T, a, b string) {
- data, err := diff([]byte(a), []byte(b))
+ data, err := diff.Diff("go-fix-test", []byte(a), []byte(b))
if err != nil {
t.Error(err)
return
diff --git a/src/cmd/go/internal/modfile/read_test.go b/src/cmd/go/internal/modfile/read_test.go
index 32401304b9..3c88e69281 100644
--- a/src/cmd/go/internal/modfile/read_test.go
+++ b/src/cmd/go/internal/modfile/read_test.go
@@ -9,11 +9,12 @@ import (
"fmt"
"io/ioutil"
"os"
- "os/exec"
"path/filepath"
"reflect"
"strings"
"testing"
+
+ "cmd/internal/diff"
)
// exists reports whether the named file exists.
@@ -282,37 +283,9 @@ func (eq *eqchecker) checkValue(v, w reflect.Value) error {
return nil
}
-// diff returns the output of running diff on b1 and b2.
-func diff(b1, b2 []byte) (data []byte, err error) {
- f1, err := ioutil.TempFile("", "testdiff")
- if err != nil {
- return nil, err
- }
- defer os.Remove(f1.Name())
- defer f1.Close()
-
- f2, err := ioutil.TempFile("", "testdiff")
- if err != nil {
- return nil, err
- }
- defer os.Remove(f2.Name())
- defer f2.Close()
-
- f1.Write(b1)
- f2.Write(b2)
-
- data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
- if len(data) > 0 {
- // diff exits with a non-zero status when the files don't match.
- // Ignore that failure as long as we get output.
- err = nil
- }
- return
-}
-
// tdiff logs the diff output to t.Error.
func tdiff(t *testing.T, a, b string) {
- data, err := diff([]byte(a), []byte(b))
+ data, err := diff.Diff("modfile-test", []byte(a), []byte(b))
if err != nil {
t.Error(err)
return
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index d7a77a9682..9e472b2d51 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -16,11 +16,12 @@ import (
"io"
"io/ioutil"
"os"
- "os/exec"
"path/filepath"
"runtime"
"runtime/pprof"
"strings"
+
+ "cmd/internal/diff"
)
var (
@@ -141,7 +142,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
}
}
if *doDiff {
- data, err := diff(src, res, filename)
+ data, err := diffWithReplaceTempFile(src, res, filename)
if err != nil {
return fmt.Errorf("computing diff: %s", err)
}
@@ -227,47 +228,12 @@ func gofmtMain() {
}
}
-func writeTempFile(dir, prefix string, data []byte) (string, error) {
- file, err := ioutil.TempFile(dir, prefix)
- if err != nil {
- return "", err
- }
- _, err = file.Write(data)
- if err1 := file.Close(); err == nil {
- err = err1
- }
- if err != nil {
- os.Remove(file.Name())
- return "", err
- }
- return file.Name(), nil
-}
-
-func diff(b1, b2 []byte, filename string) (data []byte, err error) {
- f1, err := writeTempFile("", "gofmt", b1)
- if err != nil {
- return
- }
- defer os.Remove(f1)
-
- f2, err := writeTempFile("", "gofmt", b2)
- if err != nil {
- return
- }
- defer os.Remove(f2)
-
- cmd := "diff"
- if runtime.GOOS == "plan9" {
- cmd = "/bin/ape/diff"
- }
-
- data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput()
+func diffWithReplaceTempFile(b1, b2 []byte, filename string) ([]byte, error) {
+ data, err := diff.Diff("gofmt", b1, b2)
if len(data) > 0 {
- // diff exits with a non-zero status when the files don't match.
- // Ignore that failure as long as we get output.
return replaceTempFilename(data, filename)
}
- return
+ return data, err
}
// replaceTempFilename replaces temporary filenames in diff with actual one.
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index 3008365cd2..98d3eb7eb2 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -112,7 +112,7 @@ func runTest(t *testing.T, in, out string) {
}
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
- d, err := diff(expected, got, in)
+ d, err := diffWithReplaceTempFile(expected, got, in)
if err == nil {
t.Errorf("%s", d)
}
@@ -194,7 +194,7 @@ func TestDiff(t *testing.T) {
in := []byte("first\nsecond\n")
out := []byte("first\nthird\n")
filename := "difftest.txt"
- b, err := diff(in, out, filename)
+ b, err := diffWithReplaceTempFile(in, out, filename)
if err != nil {
t.Fatal(err)
}
diff --git a/src/cmd/internal/diff/diff.go b/src/cmd/internal/diff/diff.go
new file mode 100644
index 0000000000..e9d2c23780
--- /dev/null
+++ b/src/cmd/internal/diff/diff.go
@@ -0,0 +1,58 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package diff implements a Diff function that compare two inputs
+// using the 'diff' tool.
+package diff
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "runtime"
+)
+
+// Returns diff of two arrays of bytes in diff tool format.
+func Diff(prefix string, b1, b2 []byte) ([]byte, error) {
+ f1, err := writeTempFile(prefix, b1)
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(f1)
+
+ f2, err := writeTempFile(prefix, b2)
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(f2)
+
+ cmd := "diff"
+ if runtime.GOOS == "plan9" {
+ cmd = "/bin/ape/diff"
+ }
+
+ data, err := exec.Command(cmd, "-u", f1, f2).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
+ }
+ return data, err
+}
+
+func writeTempFile(prefix string, data []byte) (string, error) {
+ file, err := ioutil.TempFile("", prefix)
+ if err != nil {
+ return "", err
+ }
+ _, err = file.Write(data)
+ if err1 := file.Close(); err == nil {
+ err = err1
+ }
+ if err != nil {
+ os.Remove(file.Name())
+ return "", err
+ }
+ return file.Name(), nil
+}
--
cgit v1.3-5-g9baa
From d2101e54908dc6899863be0772658dbd7e0bbc71 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Wed, 23 Oct 2019 09:47:53 -0400
Subject: runtime/internal/atomic: add Store8
We already have Load8, And8, and Or8.
For #10958, #24543, but makes sense on its own.
Change-Id: I478529fc643edc57efdeccaae413c99edd19b2eb
Reviewed-on: https://go-review.googlesource.com/c/go/+/203283
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/runtime/internal/atomic/asm_386.s | 6 ++++++
src/runtime/internal/atomic/asm_amd64.s | 6 ++++++
src/runtime/internal/atomic/asm_mips64x.s | 8 ++++++++
src/runtime/internal/atomic/asm_mipsx.s | 8 ++++++++
src/runtime/internal/atomic/asm_ppc64x.s | 7 +++++++
src/runtime/internal/atomic/asm_s390x.s | 8 ++++++++
src/runtime/internal/atomic/atomic_386.go | 3 +++
src/runtime/internal/atomic/atomic_amd64.go | 3 +++
src/runtime/internal/atomic/atomic_arm.go | 3 +++
src/runtime/internal/atomic/atomic_arm64.go | 3 +++
src/runtime/internal/atomic/atomic_arm64.s | 6 ++++++
src/runtime/internal/atomic/atomic_mips64x.go | 3 +++
src/runtime/internal/atomic/atomic_mipsx.go | 3 +++
src/runtime/internal/atomic/atomic_ppc64x.go | 3 +++
src/runtime/internal/atomic/atomic_s390x.go | 3 +++
src/runtime/internal/atomic/atomic_wasm.go | 6 ++++++
src/runtime/internal/atomic/sys_linux_arm.s | 22 ++++++++++++++++++++++
src/runtime/internal/atomic/sys_nonlinux_arm.s | 17 +++++++++++++++++
18 files changed, 118 insertions(+)
(limited to 'src')
diff --git a/src/runtime/internal/atomic/asm_386.s b/src/runtime/internal/atomic/asm_386.s
index 13289a88d0..9b9dc14a60 100644
--- a/src/runtime/internal/atomic/asm_386.s
+++ b/src/runtime/internal/atomic/asm_386.s
@@ -229,3 +229,9 @@ TEXT runtime∕internal∕atomic·And8(SB), NOSPLIT, $0-5
LOCK
ANDB BX, (AX)
RET
+
+TEXT runtime∕internal∕atomic·Store8(SB), NOSPLIT, $0-5
+ MOVL ptr+0(FP), BX
+ MOVB val+4(FP), AX
+ XCHGB AX, 0(BX)
+ RET
diff --git a/src/runtime/internal/atomic/asm_amd64.s b/src/runtime/internal/atomic/asm_amd64.s
index e18aee7d59..90c56424c9 100644
--- a/src/runtime/internal/atomic/asm_amd64.s
+++ b/src/runtime/internal/atomic/asm_amd64.s
@@ -136,6 +136,12 @@ TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12
TEXT runtime∕internal∕atomic·StoreRel(SB), NOSPLIT, $0-12
JMP runtime∕internal∕atomic·Store(SB)
+TEXT runtime∕internal∕atomic·Store8(SB), NOSPLIT, $0-9
+ MOVQ ptr+0(FP), BX
+ MOVB val+8(FP), AX
+ XCHGB AX, 0(BX)
+ RET
+
TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-16
MOVQ ptr+0(FP), BX
MOVQ val+8(FP), AX
diff --git a/src/runtime/internal/atomic/asm_mips64x.s b/src/runtime/internal/atomic/asm_mips64x.s
index 9cb10371b7..3290fb726a 100644
--- a/src/runtime/internal/atomic/asm_mips64x.s
+++ b/src/runtime/internal/atomic/asm_mips64x.s
@@ -166,6 +166,14 @@ TEXT ·Store(SB), NOSPLIT, $0-12
SYNC
RET
+TEXT ·Store8(SB), NOSPLIT, $0-9
+ MOVV ptr+0(FP), R1
+ MOVB val+8(FP), R2
+ SYNC
+ MOVB R2, 0(R1)
+ SYNC
+ RET
+
TEXT ·Store64(SB), NOSPLIT, $0-16
MOVV ptr+0(FP), R1
MOVV val+8(FP), R2
diff --git a/src/runtime/internal/atomic/asm_mipsx.s b/src/runtime/internal/atomic/asm_mipsx.s
index af6bce57d6..62811a6599 100644
--- a/src/runtime/internal/atomic/asm_mipsx.s
+++ b/src/runtime/internal/atomic/asm_mipsx.s
@@ -32,6 +32,14 @@ TEXT ·Store(SB),NOSPLIT,$0-8
SYNC
RET
+TEXT ·Store8(SB),NOSPLIT,$0-5
+ MOVW ptr+0(FP), R1
+ MOVB val+4(FP), R2
+ SYNC
+ MOVB R2, 0(R1)
+ SYNC
+ RET
+
TEXT ·Load(SB),NOSPLIT,$0-8
MOVW ptr+0(FP), R1
SYNC
diff --git a/src/runtime/internal/atomic/asm_ppc64x.s b/src/runtime/internal/atomic/asm_ppc64x.s
index 052b031cfb..06dc931bf4 100644
--- a/src/runtime/internal/atomic/asm_ppc64x.s
+++ b/src/runtime/internal/atomic/asm_ppc64x.s
@@ -170,6 +170,13 @@ TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12
MOVW R4, 0(R3)
RET
+TEXT runtime∕internal∕atomic·Store8(SB), NOSPLIT, $0-9
+ MOVD ptr+0(FP), R3
+ MOVB val+8(FP), R4
+ SYNC
+ MOVB R4, 0(R3)
+ RET
+
TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-16
MOVD ptr+0(FP), R3
MOVD val+8(FP), R4
diff --git a/src/runtime/internal/atomic/asm_s390x.s b/src/runtime/internal/atomic/asm_s390x.s
index 084f5b5163..78abd48afa 100644
--- a/src/runtime/internal/atomic/asm_s390x.s
+++ b/src/runtime/internal/atomic/asm_s390x.s
@@ -12,6 +12,14 @@ TEXT ·Store(SB), NOSPLIT, $0
SYNC
RET
+// func Store8(ptr *uint8, val uint8)
+TEXT ·Store8(SB), NOSPLIT, $0
+ MOVD ptr+0(FP), R2
+ MOVB val+8(FP), R3
+ MOVB R3, 0(R2)
+ SYNC
+ RET
+
// func Store64(ptr *uint64, val uint64)
TEXT ·Store64(SB), NOSPLIT, $0
MOVD ptr+0(FP), R2
diff --git a/src/runtime/internal/atomic/atomic_386.go b/src/runtime/internal/atomic/atomic_386.go
index d7f82cc752..8d002ebfe3 100644
--- a/src/runtime/internal/atomic/atomic_386.go
+++ b/src/runtime/internal/atomic/atomic_386.go
@@ -74,6 +74,9 @@ func CasRel(ptr *uint32, old, new uint32) bool
//go:noescape
func Store(ptr *uint32, val uint32)
+//go:noescape
+func Store8(ptr *uint8, val uint8)
+
//go:noescape
func Store64(ptr *uint64, val uint64)
diff --git a/src/runtime/internal/atomic/atomic_amd64.go b/src/runtime/internal/atomic/atomic_amd64.go
index fc865e892d..14b8101720 100644
--- a/src/runtime/internal/atomic/atomic_amd64.go
+++ b/src/runtime/internal/atomic/atomic_amd64.go
@@ -76,6 +76,9 @@ func CasRel(ptr *uint32, old, new uint32) bool
//go:noescape
func Store(ptr *uint32, val uint32)
+//go:noescape
+func Store8(ptr *uint8, val uint8)
+
//go:noescape
func Store64(ptr *uint64, val uint64)
diff --git a/src/runtime/internal/atomic/atomic_arm.go b/src/runtime/internal/atomic/atomic_arm.go
index c1fc1f727f..95713afcc1 100644
--- a/src/runtime/internal/atomic/atomic_arm.go
+++ b/src/runtime/internal/atomic/atomic_arm.go
@@ -209,5 +209,8 @@ func Xchg64(addr *uint64, v uint64) uint64
//go:noescape
func Load64(addr *uint64) uint64
+//go:noescape
+func Store8(addr *uint8, v uint8)
+
//go:noescape
func Store64(addr *uint64, v uint64)
diff --git a/src/runtime/internal/atomic/atomic_arm64.go b/src/runtime/internal/atomic/atomic_arm64.go
index 0182f309cc..26ca94d54c 100644
--- a/src/runtime/internal/atomic/atomic_arm64.go
+++ b/src/runtime/internal/atomic/atomic_arm64.go
@@ -56,6 +56,9 @@ func CasRel(ptr *uint32, old, new uint32) bool
//go:noescape
func Store(ptr *uint32, val uint32)
+//go:noescape
+func Store8(ptr *uint8, val uint8)
+
//go:noescape
func Store64(ptr *uint64, val uint64)
diff --git a/src/runtime/internal/atomic/atomic_arm64.s b/src/runtime/internal/atomic/atomic_arm64.s
index a7e8c35449..d95689fe2d 100644
--- a/src/runtime/internal/atomic/atomic_arm64.s
+++ b/src/runtime/internal/atomic/atomic_arm64.s
@@ -48,6 +48,12 @@ TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12
STLRW R1, (R0)
RET
+TEXT runtime∕internal∕atomic·Store8(SB), NOSPLIT, $0-9
+ MOVD ptr+0(FP), R0
+ MOVB val+8(FP), R1
+ STLRB R1, (R0)
+ RET
+
TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-16
MOVD ptr+0(FP), R0
MOVD val+8(FP), R1
diff --git a/src/runtime/internal/atomic/atomic_mips64x.go b/src/runtime/internal/atomic/atomic_mips64x.go
index ce11e38a96..1d9977850b 100644
--- a/src/runtime/internal/atomic/atomic_mips64x.go
+++ b/src/runtime/internal/atomic/atomic_mips64x.go
@@ -58,6 +58,9 @@ func CasRel(ptr *uint32, old, new uint32) bool
//go:noescape
func Store(ptr *uint32, val uint32)
+//go:noescape
+func Store8(ptr *uint8, val uint8)
+
//go:noescape
func Store64(ptr *uint64, val uint64)
diff --git a/src/runtime/internal/atomic/atomic_mipsx.go b/src/runtime/internal/atomic/atomic_mipsx.go
index 6e39262c15..0e2d77ade1 100644
--- a/src/runtime/internal/atomic/atomic_mipsx.go
+++ b/src/runtime/internal/atomic/atomic_mipsx.go
@@ -141,6 +141,9 @@ func Or8(ptr *uint8, val uint8)
//go:noescape
func Store(ptr *uint32, val uint32)
+//go:noescape
+func Store8(ptr *uint8, val uint8)
+
// NO go:noescape annotation; see atomic_pointer.go.
func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/internal/atomic/atomic_ppc64x.go b/src/runtime/internal/atomic/atomic_ppc64x.go
index 13805a5275..a48ecf5ee8 100644
--- a/src/runtime/internal/atomic/atomic_ppc64x.go
+++ b/src/runtime/internal/atomic/atomic_ppc64x.go
@@ -58,6 +58,9 @@ func CasRel(ptr *uint32, old, new uint32) bool
//go:noescape
func Store(ptr *uint32, val uint32)
+//go:noescape
+func Store8(ptr *uint8, val uint8)
+
//go:noescape
func Store64(ptr *uint64, val uint64)
diff --git a/src/runtime/internal/atomic/atomic_s390x.go b/src/runtime/internal/atomic/atomic_s390x.go
index 25fd890524..4d73b39baf 100644
--- a/src/runtime/internal/atomic/atomic_s390x.go
+++ b/src/runtime/internal/atomic/atomic_s390x.go
@@ -44,6 +44,9 @@ func LoadAcq(ptr *uint32) uint32 {
//go:noescape
func Store(ptr *uint32, val uint32)
+//go:noescape
+func Store8(ptr *uint8, val uint8)
+
//go:noescape
func Store64(ptr *uint64, val uint64)
diff --git a/src/runtime/internal/atomic/atomic_wasm.go b/src/runtime/internal/atomic/atomic_wasm.go
index 0731763ac1..9037c2f7c8 100644
--- a/src/runtime/internal/atomic/atomic_wasm.go
+++ b/src/runtime/internal/atomic/atomic_wasm.go
@@ -141,6 +141,12 @@ func StoreRel(ptr *uint32, val uint32) {
*ptr = val
}
+//go:nosplit
+//go:noinline
+func Store8(ptr *uint8, val uint8) {
+ *ptr = val
+}
+
//go:nosplit
//go:noinline
func Store64(ptr *uint64, val uint64) {
diff --git a/src/runtime/internal/atomic/sys_linux_arm.s b/src/runtime/internal/atomic/sys_linux_arm.s
index df62f6c8ad..0c1cc3dc86 100644
--- a/src/runtime/internal/atomic/sys_linux_arm.s
+++ b/src/runtime/internal/atomic/sys_linux_arm.s
@@ -120,3 +120,25 @@ end:
MOVB R1, ret+4(FP)
RET
+TEXT ·Store8(SB),NOSPLIT,$0-5
+ MOVW addr+0(FP), R1
+ MOVB v+4(FP), R2
+
+ MOVB runtime·goarm(SB), R8
+ CMP $7, R8
+ BGE native_barrier
+ BL memory_barrier<>(SB)
+ B store
+native_barrier:
+ DMB MB_ISH
+
+store:
+ MOVB R2, (R1)
+
+ CMP $7, R8
+ BGE native_barrier2
+ BL memory_barrier<>(SB)
+ RET
+native_barrier2:
+ DMB MB_ISH
+ RET
diff --git a/src/runtime/internal/atomic/sys_nonlinux_arm.s b/src/runtime/internal/atomic/sys_nonlinux_arm.s
index 9d81334791..57568b2238 100644
--- a/src/runtime/internal/atomic/sys_nonlinux_arm.s
+++ b/src/runtime/internal/atomic/sys_nonlinux_arm.s
@@ -60,3 +60,20 @@ TEXT ·Load8(SB),NOSPLIT|NOFRAME,$0-5
MOVB R1, ret+4(FP)
RET
+
+TEXT ·Store8(SB),NOSPLIT,$0-5
+ MOVW addr+0(FP), R1
+ MOVB v+4(FP), R2
+
+ MOVB runtime·goarm(SB), R8
+ CMP $7, R8
+ BLT 2(PC)
+ DMB MB_ISH
+
+ MOVB R2, (R1)
+
+ CMP $7, R8
+ BLT 2(PC)
+ DMB MB_ISH
+ RET
+
--
cgit v1.3-5-g9baa
From 97592b3c14e96eece91ddc91a188e08fd2ed2dfa Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Wed, 23 Oct 2019 10:20:49 -0400
Subject: cmd/compile: intrinsics for runtime/internal/atomic.Store8
For #10958, #24543, but makes sense on its own.
Change-Id: I2a87dab66b82a1863e4b6512b1f8def51463ce2a
Reviewed-on: https://go-review.googlesource.com/c/go/+/203284
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/cmd/compile/internal/amd64/ssa.go | 2 +-
src/cmd/compile/internal/arm64/ssa.go | 1 +
src/cmd/compile/internal/gc/ssa.go | 8 ++-
src/cmd/compile/internal/mips64/ssa.go | 7 ++-
src/cmd/compile/internal/ppc64/ssa.go | 10 ++-
src/cmd/compile/internal/s390x/ssa.go | 2 +-
src/cmd/compile/internal/ssa/gen/AMD64.rules | 1 +
src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 1 +
src/cmd/compile/internal/ssa/gen/ARM64.rules | 1 +
src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 1 +
src/cmd/compile/internal/ssa/gen/MIPS64.rules | 1 +
src/cmd/compile/internal/ssa/gen/MIPS64Ops.go | 1 +
src/cmd/compile/internal/ssa/gen/PPC64.rules | 2 +-
src/cmd/compile/internal/ssa/gen/PPC64Ops.go | 1 +
src/cmd/compile/internal/ssa/gen/S390X.rules | 2 +-
src/cmd/compile/internal/ssa/gen/S390XOps.go | 1 +
src/cmd/compile/internal/ssa/gen/genericOps.go | 1 +
src/cmd/compile/internal/ssa/opGen.go | 85 ++++++++++++++++++++++++++
src/cmd/compile/internal/ssa/rewriteAMD64.go | 20 ++++++
src/cmd/compile/internal/ssa/rewriteARM64.go | 16 +++++
src/cmd/compile/internal/ssa/rewriteMIPS64.go | 16 +++++
src/cmd/compile/internal/ssa/rewritePPC64.go | 17 ++++++
src/cmd/compile/internal/ssa/rewriteS390X.go | 19 ++++++
23 files changed, 206 insertions(+), 10 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index 480ff6523a..088a4a16c7 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -1091,7 +1091,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg0()
- case ssa.OpAMD64XCHGL, ssa.OpAMD64XCHGQ:
+ case ssa.OpAMD64XCHGB, ssa.OpAMD64XCHGL, ssa.OpAMD64XCHGQ:
r := v.Reg0()
if r != v.Args[0].Reg() {
v.Fatalf("input[0] and output[0] not in same register %s", v.LongString())
diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go
index 252e875669..24b6383bbc 100644
--- a/src/cmd/compile/internal/arm64/ssa.go
+++ b/src/cmd/compile/internal/arm64/ssa.go
@@ -452,6 +452,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpARM64MOVDstore,
ssa.OpARM64FMOVSstore,
ssa.OpARM64FMOVDstore,
+ ssa.OpARM64STLRB,
ssa.OpARM64STLR,
ssa.OpARM64STLRW:
p := s.Prog(v.Op.Asm())
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index dff559a7ba..d1eef69189 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -3337,7 +3337,7 @@ func init() {
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
return s.newValue1(ssa.OpSelect0, types.Types[TUINT8], v)
},
- sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64)
+ sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64)
addF("runtime/internal/atomic", "Load64",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
v := s.newValue2(ssa.OpAtomicLoad64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
@@ -3366,6 +3366,12 @@ func init() {
return nil
},
sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64)
+ addF("runtime/internal/atomic", "Store8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore8, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64)
addF("runtime/internal/atomic", "Store64",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore64, types.TypeMem, args[0], args[1], s.mem())
diff --git a/src/cmd/compile/internal/mips64/ssa.go b/src/cmd/compile/internal/mips64/ssa.go
index a70db3576c..28652f0cc4 100644
--- a/src/cmd/compile/internal/mips64/ssa.go
+++ b/src/cmd/compile/internal/mips64/ssa.go
@@ -516,9 +516,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg0()
s.Prog(mips.ASYNC)
- case ssa.OpMIPS64LoweredAtomicStore32, ssa.OpMIPS64LoweredAtomicStore64:
+ case ssa.OpMIPS64LoweredAtomicStore8, ssa.OpMIPS64LoweredAtomicStore32, ssa.OpMIPS64LoweredAtomicStore64:
as := mips.AMOVV
- if v.Op == ssa.OpMIPS64LoweredAtomicStore32 {
+ switch v.Op {
+ case ssa.OpMIPS64LoweredAtomicStore8:
+ as = mips.AMOVB
+ case ssa.OpMIPS64LoweredAtomicStore32:
as = mips.AMOVW
}
s.Prog(mips.ASYNC)
diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go
index 4f852b883a..4af6e9d5ed 100644
--- a/src/cmd/compile/internal/ppc64/ssa.go
+++ b/src/cmd/compile/internal/ppc64/ssa.go
@@ -335,12 +335,16 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
pisync.To.Type = obj.TYPE_NONE
gc.Patch(p2, pisync)
- case ssa.OpPPC64LoweredAtomicStore32,
+ case ssa.OpPPC64LoweredAtomicStore8,
+ ssa.OpPPC64LoweredAtomicStore32,
ssa.OpPPC64LoweredAtomicStore64:
// SYNC or LWSYNC
- // MOVD/MOVW arg1,(arg0)
+ // MOVB/MOVW/MOVD arg1,(arg0)
st := ppc64.AMOVD
- if v.Op == ssa.OpPPC64LoweredAtomicStore32 {
+ switch v.Op {
+ case ssa.OpPPC64LoweredAtomicStore8:
+ st = ppc64.AMOVB
+ case ssa.OpPPC64LoweredAtomicStore32:
st = ppc64.AMOVW
}
arg0 := v.Args[0].Reg()
diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go
index 2be6c1ab94..af45a561c6 100644
--- a/src/cmd/compile/internal/s390x/ssa.go
+++ b/src/cmd/compile/internal/s390x/ssa.go
@@ -725,7 +725,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg0()
- case ssa.OpS390XMOVWatomicstore, ssa.OpS390XMOVDatomicstore:
+ case ssa.OpS390XMOVBatomicstore, ssa.OpS390XMOVWatomicstore, ssa.OpS390XMOVDatomicstore:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[1].Reg()
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index d4484084a1..c4f8757021 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -533,6 +533,7 @@
// Atomic stores. We use XCHG to prevent the hardware reordering a subsequent load.
// TODO: most runtime uses of atomic stores don't need that property. Use normal stores for those?
+(AtomicStore8 ptr val mem) -> (Select1 (XCHGB val ptr mem))
(AtomicStore32 ptr val mem) -> (Select1 (XCHGL val ptr mem))
(AtomicStore64 ptr val mem) -> (Select1 (XCHGQ val ptr mem))
(AtomicStorePtrNoWB ptr val mem) && config.PtrSize == 8 -> (Select1 (XCHGQ val ptr mem))
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index 5924fa497a..cd2d0d61d1 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -746,6 +746,7 @@ func init() {
// store arg0 to arg1+auxint+aux, arg2=mem.
// These ops return a tuple of .
// Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)!
+ {name: "XCHGB", argLength: 3, reg: gpstorexchg, asm: "XCHGB", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"},
{name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"},
{name: "XCHGQ", argLength: 3, reg: gpstorexchg, asm: "XCHGQ", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"},
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index 26ae004572..f0033a0526 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -589,6 +589,7 @@
(AtomicLoad64 ptr mem) -> (LDAR ptr mem)
(AtomicLoadPtr ptr mem) -> (LDAR ptr mem)
+(AtomicStore8 ptr val mem) -> (STLRB ptr val mem)
(AtomicStore32 ptr val mem) -> (STLRW ptr val mem)
(AtomicStore64 ptr val mem) -> (STLR ptr val mem)
(AtomicStorePtrNoWB ptr val mem) -> (STLR ptr val mem)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
index e1f045fcf8..59a6004b97 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
@@ -611,6 +611,7 @@ func init() {
// atomic stores.
// store arg1 to arg0. arg2=mem. returns memory. auxint must be zero.
+ {name: "STLRB", argLength: 3, reg: gpstore, asm: "STLRB", faultOnNilArg0: true, hasSideEffects: true},
{name: "STLR", argLength: 3, reg: gpstore, asm: "STLR", faultOnNilArg0: true, hasSideEffects: true},
{name: "STLRW", argLength: 3, reg: gpstore, asm: "STLRW", faultOnNilArg0: true, hasSideEffects: true},
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
index f3d0a08e28..4e5b9d8104 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules
+++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
@@ -403,6 +403,7 @@
(AtomicLoad64 ptr mem) -> (LoweredAtomicLoad64 ptr mem)
(AtomicLoadPtr ptr mem) -> (LoweredAtomicLoad64 ptr mem)
+(AtomicStore8 ptr val mem) -> (LoweredAtomicStore8 ptr val mem)
(AtomicStore32 ptr val mem) -> (LoweredAtomicStore32 ptr val mem)
(AtomicStore64 ptr val mem) -> (LoweredAtomicStore64 ptr val mem)
(AtomicStorePtrNoWB ptr val mem) -> (LoweredAtomicStore64 ptr val mem)
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
index 184b119f89..a5eabcf9eb 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
@@ -367,6 +367,7 @@ func init() {
// atomic stores.
// store arg1 to arg0. arg2=mem. returns memory.
+ {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
// store zero to arg0. arg1=mem. returns memory.
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index 239414f01b..13fe1ab2e9 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -931,7 +931,7 @@
(AtomicLoad(8|32|64|Ptr) ptr mem) -> (LoweredAtomicLoad(8|32|64|Ptr) [1] ptr mem)
(AtomicLoadAcq32 ptr mem) -> (LoweredAtomicLoad32 [0] ptr mem)
-(AtomicStore(32|64) ptr val mem) -> (LoweredAtomicStore(32|64) [1] ptr val mem)
+(AtomicStore(8|32|64) ptr val mem) -> (LoweredAtomicStore(8|32|64) [1] ptr val mem)
(AtomicStoreRel32 ptr val mem) -> (LoweredAtomicStore32 [0] ptr val mem)
//(AtomicStorePtrNoWB ptr val mem) -> (STLR ptr val mem)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
index a6bcc26543..b72563b53c 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
@@ -495,6 +495,7 @@ func init() {
faultOnNilArg1: true,
},
+ {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", aux: "Int64", faultOnNilArg0: true, hasSideEffects: true},
diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules
index d7cb972b81..2c56c66581 100644
--- a/src/cmd/compile/internal/ssa/gen/S390X.rules
+++ b/src/cmd/compile/internal/ssa/gen/S390X.rules
@@ -146,7 +146,7 @@
// reordering. Other sequences of memory operations (load-load,
// store-store and load-store) are already guaranteed not to be reordered.
(AtomicLoad(8|32|Acq32|64|Ptr) ptr mem) -> (MOV(BZ|WZ|WZ|D|D)atomicload ptr mem)
-(AtomicStore(32|64|PtrNoWB) ptr val mem) -> (SYNC (MOV(W|D|D)atomicstore ptr val mem))
+(AtomicStore(8|32|64|PtrNoWB) ptr val mem) -> (SYNC (MOV(B|W|D|D)atomicstore ptr val mem))
// Store-release doesn't require store-load ordering.
(AtomicStoreRel32 ptr val mem) -> (MOVWatomicstore ptr val mem)
diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go
index 4689102c43..4adaeae242 100644
--- a/src/cmd/compile/internal/ssa/gen/S390XOps.go
+++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go
@@ -495,6 +495,7 @@ func init() {
// Atomic stores. These are just normal stores.
// store arg1 to arg0+auxint+aux. arg2=mem.
+ {name: "MOVBatomicstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"},
{name: "MOVWatomicstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"},
{name: "MOVDatomicstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "Write"},
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index 748805f369..1ffca8118f 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -545,6 +545,7 @@ var genericOps = []opData{
{name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
{name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
{name: "AtomicLoadAcq32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Lock acquisition, returns loaded value and new memory.
+ {name: "AtomicStore8", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStore32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStore64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 1bac391914..5077e80a15 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -877,6 +877,7 @@ const (
OpAMD64MOVBatomicload
OpAMD64MOVLatomicload
OpAMD64MOVQatomicload
+ OpAMD64XCHGB
OpAMD64XCHGL
OpAMD64XCHGQ
OpAMD64XADDLlock
@@ -1434,6 +1435,7 @@ const (
OpARM64LDAR
OpARM64LDARB
OpARM64LDARW
+ OpARM64STLRB
OpARM64STLR
OpARM64STLRW
OpARM64LoweredAtomicExchange64
@@ -1655,6 +1657,7 @@ const (
OpMIPS64LoweredAtomicLoad8
OpMIPS64LoweredAtomicLoad32
OpMIPS64LoweredAtomicLoad64
+ OpMIPS64LoweredAtomicStore8
OpMIPS64LoweredAtomicStore32
OpMIPS64LoweredAtomicStore64
OpMIPS64LoweredAtomicStorezero32
@@ -1848,6 +1851,7 @@ const (
OpPPC64CALLinter
OpPPC64LoweredZero
OpPPC64LoweredMove
+ OpPPC64LoweredAtomicStore8
OpPPC64LoweredAtomicStore32
OpPPC64LoweredAtomicStore64
OpPPC64LoweredAtomicLoad8
@@ -2068,6 +2072,7 @@ const (
OpS390XMOVBZatomicload
OpS390XMOVWZatomicload
OpS390XMOVDatomicload
+ OpS390XMOVBatomicstore
OpS390XMOVWatomicstore
OpS390XMOVDatomicstore
OpS390XLAA
@@ -2553,6 +2558,7 @@ const (
OpAtomicLoad64
OpAtomicLoadPtr
OpAtomicLoadAcq32
+ OpAtomicStore8
OpAtomicStore32
OpAtomicStore64
OpAtomicStorePtrNoWB
@@ -11406,6 +11412,25 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "XCHGB",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ faultOnNilArg1: true,
+ hasSideEffects: true,
+ symEffect: SymRdWr,
+ asm: x86.AXCHGB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
{
name: "XCHGL",
auxType: auxSymOff,
@@ -18876,6 +18901,19 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "STLRB",
+ argLen: 3,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ asm: arm64.ASTLRB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB
+ },
+ },
+ },
{
name: "STLR",
argLen: 3,
@@ -21882,6 +21920,18 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "LoweredAtomicStore8",
+ argLen: 3,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 234881022}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 g R31
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
{
name: "LoweredAtomicStore32",
argLen: 3,
@@ -24489,6 +24539,19 @@ var opcodeTable = [...]opInfo{
clobbers: 16408, // R3 R4 R14
},
},
+ {
+ name: "LoweredAtomicStore8",
+ auxType: auxInt64,
+ argLen: 3,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
{
name: "LoweredAtomicStore32",
auxType: auxInt64,
@@ -27632,6 +27695,22 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "MOVBatomicstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ symEffect: SymWrite,
+ asm: s390x.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295023614}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 SP SB
+ {1, 56319}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 SP
+ },
+ },
+ },
{
name: "MOVWatomicstore",
auxType: auxSymOff,
@@ -31347,6 +31426,12 @@ var opcodeTable = [...]opInfo{
argLen: 2,
generic: true,
},
+ {
+ name: "AtomicStore8",
+ argLen: 3,
+ hasSideEffects: true,
+ generic: true,
+ },
{
name: "AtomicStore32",
argLen: 3,
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index 45634a25eb..bacfced207 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -646,6 +646,8 @@ func rewriteValueAMD64(v *Value) bool {
return rewriteValueAMD64_OpAtomicStore32_0(v)
case OpAtomicStore64:
return rewriteValueAMD64_OpAtomicStore64_0(v)
+ case OpAtomicStore8:
+ return rewriteValueAMD64_OpAtomicStore8_0(v)
case OpAtomicStorePtrNoWB:
return rewriteValueAMD64_OpAtomicStorePtrNoWB_0(v)
case OpAvg64u:
@@ -50391,6 +50393,24 @@ func rewriteValueAMD64_OpAtomicStore64_0(v *Value) bool {
return true
}
}
+func rewriteValueAMD64_OpAtomicStore8_0(v *Value) bool {
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (AtomicStore8 ptr val mem)
+ // result: (Select1 (XCHGB val ptr mem))
+ for {
+ mem := v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ v.reset(OpSelect1)
+ v0 := b.NewValue0(v.Pos, OpAMD64XCHGB, types.NewTuple(typ.UInt8, types.TypeMem))
+ v0.AddArg(val)
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ return true
+ }
+}
func rewriteValueAMD64_OpAtomicStorePtrNoWB_0(v *Value) bool {
b := v.Block
config := b.Func.Config
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index a5f74fab51..e9bde5ec8a 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -431,6 +431,8 @@ func rewriteValueARM64(v *Value) bool {
return rewriteValueARM64_OpAtomicStore32_0(v)
case OpAtomicStore64:
return rewriteValueARM64_OpAtomicStore64_0(v)
+ case OpAtomicStore8:
+ return rewriteValueARM64_OpAtomicStore8_0(v)
case OpAtomicStorePtrNoWB:
return rewriteValueARM64_OpAtomicStorePtrNoWB_0(v)
case OpAvg64u:
@@ -27669,6 +27671,20 @@ func rewriteValueARM64_OpAtomicStore64_0(v *Value) bool {
return true
}
}
+func rewriteValueARM64_OpAtomicStore8_0(v *Value) bool {
+ // match: (AtomicStore8 ptr val mem)
+ // result: (STLRB ptr val mem)
+ for {
+ mem := v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ v.reset(OpARM64STLRB)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
func rewriteValueARM64_OpAtomicStorePtrNoWB_0(v *Value) bool {
// match: (AtomicStorePtrNoWB ptr val mem)
// result: (STLR ptr val mem)
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
index 08b1f43841..869ccd3b19 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
@@ -57,6 +57,8 @@ func rewriteValueMIPS64(v *Value) bool {
return rewriteValueMIPS64_OpAtomicStore32_0(v)
case OpAtomicStore64:
return rewriteValueMIPS64_OpAtomicStore64_0(v)
+ case OpAtomicStore8:
+ return rewriteValueMIPS64_OpAtomicStore8_0(v)
case OpAtomicStorePtrNoWB:
return rewriteValueMIPS64_OpAtomicStorePtrNoWB_0(v)
case OpAvg64u:
@@ -938,6 +940,20 @@ func rewriteValueMIPS64_OpAtomicStore64_0(v *Value) bool {
return true
}
}
+func rewriteValueMIPS64_OpAtomicStore8_0(v *Value) bool {
+ // match: (AtomicStore8 ptr val mem)
+ // result: (LoweredAtomicStore8 ptr val mem)
+ for {
+ mem := v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ v.reset(OpMIPS64LoweredAtomicStore8)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
func rewriteValueMIPS64_OpAtomicStorePtrNoWB_0(v *Value) bool {
// match: (AtomicStorePtrNoWB ptr val mem)
// result: (LoweredAtomicStore64 ptr val mem)
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 1b462b28bb..a95364ece4 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -71,6 +71,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpAtomicStore32_0(v)
case OpAtomicStore64:
return rewriteValuePPC64_OpAtomicStore64_0(v)
+ case OpAtomicStore8:
+ return rewriteValuePPC64_OpAtomicStore8_0(v)
case OpAtomicStoreRel32:
return rewriteValuePPC64_OpAtomicStoreRel32_0(v)
case OpAvg64u:
@@ -1132,6 +1134,21 @@ func rewriteValuePPC64_OpAtomicStore64_0(v *Value) bool {
return true
}
}
+func rewriteValuePPC64_OpAtomicStore8_0(v *Value) bool {
+ // match: (AtomicStore8 ptr val mem)
+ // result: (LoweredAtomicStore8 [1] ptr val mem)
+ for {
+ mem := v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ v.reset(OpPPC64LoweredAtomicStore8)
+ v.AuxInt = 1
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
func rewriteValuePPC64_OpAtomicStoreRel32_0(v *Value) bool {
// match: (AtomicStoreRel32 ptr val mem)
// result: (LoweredAtomicStore32 [0] ptr val mem)
diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go
index 343a7381ea..645e8f2d9a 100644
--- a/src/cmd/compile/internal/ssa/rewriteS390X.go
+++ b/src/cmd/compile/internal/ssa/rewriteS390X.go
@@ -60,6 +60,8 @@ func rewriteValueS390X(v *Value) bool {
return rewriteValueS390X_OpAtomicStore32_0(v)
case OpAtomicStore64:
return rewriteValueS390X_OpAtomicStore64_0(v)
+ case OpAtomicStore8:
+ return rewriteValueS390X_OpAtomicStore8_0(v)
case OpAtomicStorePtrNoWB:
return rewriteValueS390X_OpAtomicStorePtrNoWB_0(v)
case OpAtomicStoreRel32:
@@ -1153,6 +1155,23 @@ func rewriteValueS390X_OpAtomicStore64_0(v *Value) bool {
return true
}
}
+func rewriteValueS390X_OpAtomicStore8_0(v *Value) bool {
+ b := v.Block
+ // match: (AtomicStore8 ptr val mem)
+ // result: (SYNC (MOVBatomicstore ptr val mem))
+ for {
+ mem := v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ v.reset(OpS390XSYNC)
+ v0 := b.NewValue0(v.Pos, OpS390XMOVBatomicstore, types.TypeMem)
+ v0.AddArg(ptr)
+ v0.AddArg(val)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ return true
+ }
+}
func rewriteValueS390X_OpAtomicStorePtrNoWB_0(v *Value) bool {
b := v.Block
// match: (AtomicStorePtrNoWB ptr val mem)
--
cgit v1.3-5-g9baa
From ba0bab7b4fda1498f2ace58b9d38f0fb8c748f53 Mon Sep 17 00:00:00 2001
From: Cherry Zhang
Date: Sat, 26 Oct 2019 22:48:15 -0400
Subject: cmd/internal/obj/mips: fix encoding of FCR registers
The asm encoder generally assumes that the lowest 5 bits of the
REG_XX constants match the machine instruction encoding, i.e.
the lowest 5 bits is the register number. This was not true for
FCR registers and M registers. Make it so.
MOV Rx, FCRy was encoded as two machine instructions. The first
is unnecessary. Remove.
Change-Id: Ib988e6b109ba8f564337cdd31019c1a6f1881f5b
Reviewed-on: https://go-review.googlesource.com/c/go/+/203717
Run-TryBot: Cherry Zhang
TryBot-Result: Gobot Gobot
Reviewed-by: Austin Clements
---
src/cmd/asm/internal/asm/testdata/mips64.s | 13 ++++++-----
src/cmd/internal/obj/mips/a.out.go | 35 +++++++++++++++++++++++-------
src/cmd/internal/obj/mips/asm0.go | 7 +++---
3 files changed, 37 insertions(+), 18 deletions(-)
(limited to 'src')
diff --git a/src/cmd/asm/internal/asm/testdata/mips64.s b/src/cmd/asm/internal/asm/testdata/mips64.s
index 2d1bc18cec..e80f4d83d1 100644
--- a/src/cmd/asm/internal/asm/testdata/mips64.s
+++ b/src/cmd/asm/internal/asm/testdata/mips64.s
@@ -130,27 +130,27 @@ TEXT foo(SB),DUPOK|NOSPLIT,$0
// {
// outcode(int($1), &$2, 0, &$4);
// }
- MOVW FCR0, R1
+ MOVW FCR31, R1 // 4441f800
// LMOVW freg ',' fpscr
// {
// outcode(int($1), &$2, 0, &$4);
// }
- MOVW R1, FCR0
+ MOVW R1, FCR31 // 44c1f800
// LMOVW rreg ',' mreg
// {
// outcode(int($1), &$2, 0, &$4);
// }
- MOVW R1, M1
- MOVV R1, M1
+ MOVW R1, M1 // 40810800
+ MOVV R1, M1 // 40a10800
// LMOVW mreg ',' rreg
// {
// outcode(int($1), &$2, 0, &$4);
// }
- MOVW M1, R1
- MOVV M1, R1
+ MOVW M1, R1 // 40010800
+ MOVV M1, R1 // 40210800
//
@@ -406,6 +406,7 @@ label4:
NEGW R1, R2 // 00011023
NEGV R1, R2 // 0001102f
+ RET
// END
//
diff --git a/src/cmd/internal/obj/mips/a.out.go b/src/cmd/internal/obj/mips/a.out.go
index 026e8db76a..b0205ec11a 100644
--- a/src/cmd/internal/obj/mips/a.out.go
+++ b/src/cmd/internal/obj/mips/a.out.go
@@ -46,7 +46,7 @@ const (
)
const (
- REG_R0 = obj.RBaseMIPS + iota
+ REG_R0 = obj.RBaseMIPS + iota // must be a multiple of 32
REG_R1
REG_R2
REG_R3
@@ -79,7 +79,7 @@ const (
REG_R30
REG_R31
- REG_F0
+ REG_F0 // must be a multiple of 32
REG_F1
REG_F2
REG_F3
@@ -112,11 +112,8 @@ const (
REG_F30
REG_F31
- REG_HI
- REG_LO
-
// co-processor 0 control registers
- REG_M0
+ REG_M0 // must be a multiple of 32
REG_M1
REG_M2
REG_M3
@@ -150,7 +147,7 @@ const (
REG_M31
// FPU control registers
- REG_FCR0
+ REG_FCR0 // must be a multiple of 32
REG_FCR1
REG_FCR2
REG_FCR3
@@ -183,7 +180,10 @@ const (
REG_FCR30
REG_FCR31
- REG_LAST = REG_FCR31 // the last defined register
+ REG_HI
+ REG_LO
+
+ REG_LAST = REG_LO // the last defined register
REG_SPECIAL = REG_M0
@@ -412,3 +412,22 @@ const (
AJAL = obj.ACALL
ARET = obj.ARET
)
+
+func init() {
+ // The asm encoder generally assumes that the lowest 5 bits of the
+ // REG_XX constants match the machine instruction encoding, i.e.
+ // the lowest 5 bits is the register number.
+ // Check this here.
+ if REG_R0%32 != 0 {
+ panic("REG_R0 is not a multiple of 32")
+ }
+ if REG_F0%32 != 0 {
+ panic("REG_F0 is not a multiple of 32")
+ }
+ if REG_M0%32 != 0 {
+ panic("REG_M0 is not a multiple of 32")
+ }
+ if REG_FCR0%32 != 0 {
+ panic("REG_FCR0 is not a multiple of 32")
+ }
+}
diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go
index 77aa24a4f6..76a3eec6bf 100644
--- a/src/cmd/internal/obj/mips/asm0.go
+++ b/src/cmd/internal/obj/mips/asm0.go
@@ -362,8 +362,8 @@ var optab = []Optab{
{AWORD, C_LCON, C_NONE, C_NONE, 40, 4, 0, 0},
- {AMOVW, C_REG, C_NONE, C_FCREG, 41, 8, 0, 0},
- {AMOVV, C_REG, C_NONE, C_FCREG, 41, 8, 0, sys.MIPS64},
+ {AMOVW, C_REG, C_NONE, C_FCREG, 41, 4, 0, 0},
+ {AMOVV, C_REG, C_NONE, C_FCREG, 41, 4, 0, sys.MIPS64},
{AMOVW, C_FCREG, C_NONE, C_REG, 42, 4, 0, 0},
{AMOVV, C_FCREG, C_NONE, C_REG, 42, 4, 0, sys.MIPS64},
@@ -1476,8 +1476,7 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 = uint32(c.regoff(&p.From))
case 41: /* movw f,fcr */
- o1 = OP_RRR(SP(2, 1)|(2<<21), uint32(REGZERO), uint32(0), uint32(p.To.Reg)) /* mfcc1 */
- o2 = OP_RRR(SP(2, 1)|(6<<21), uint32(p.From.Reg), uint32(0), uint32(p.To.Reg)) /* mtcc1 */
+ o1 = OP_RRR(SP(2, 1)|(6<<21), uint32(p.From.Reg), uint32(0), uint32(p.To.Reg)) /* mtcc1 */
case 42: /* movw fcr,r */
o1 = OP_RRR(SP(2, 1)|(2<<21), uint32(p.To.Reg), uint32(0), uint32(p.From.Reg)) /* mfcc1 */
--
cgit v1.3-5-g9baa
From a754d2993db1771ca3903d0a5d0e3add1883cf9b Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Mon, 28 Oct 2019 16:55:06 -0700
Subject: cmd/compile/internal/syntax: don't hardwire path separator in test
Windows uses '\' not '/'.
Fixes #35175.
Change-Id: Ib3d01dcf148fc0675496d5213f5bcc9cf210a6fc
Reviewed-on: https://go-review.googlesource.com/c/go/+/203889
Reviewed-by: Bryan C. Mills
Run-TryBot: Brad Fitzpatrick
---
src/cmd/compile/internal/syntax/parser_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go
index 3cf55defc7..673339d667 100644
--- a/src/cmd/compile/internal/syntax/parser_test.go
+++ b/src/cmd/compile/internal/syntax/parser_test.go
@@ -96,7 +96,7 @@ func walkDirs(t *testing.T, dir string, action func(string)) {
}
} else if fi.IsDir() && fi.Name() != "testdata" {
path := filepath.Join(dir, fi.Name())
- if !strings.HasSuffix(path, "/test") {
+ if !strings.HasSuffix(path, string(filepath.Separator)+"test") {
dirs = append(dirs, path)
}
}
--
cgit v1.3-5-g9baa
From 25f5044e46f5d2c9e870e37c95a13bf01c63a6b7 Mon Sep 17 00:00:00 2001
From: Cuong Manh Le
Date: Mon, 21 Oct 2019 23:25:32 +0700
Subject: cmd/compile: hard fail if n.Opt() is not nil in
walkCheckPtrArithmetic
n.Opt() is used in walkCheckPtrArithmetic to prevent infinite loops. The
fact that it's used today because n.Opt() is not used for OCONVNOP
during walk.go. If that changes, then it's not safe to repalce it
anymore. So doing hard fail if that case happens, the author of new
changes will be noticed and must change the usage of n.Opt() inside
walkCheckPtrArithmetic, too.
Change-Id: Ic7094baa1759c647fc10e82457c19026099a0d47
Reviewed-on: https://go-review.googlesource.com/c/go/+/202497
Run-TryBot: Cuong Manh Le
TryBot-Result: Gobot Gobot
Reviewed-by: Matthew Dempsky
---
src/cmd/compile/internal/gc/walk.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 0e780bad6c..2ec279bf37 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -3965,8 +3965,12 @@ func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
// Calling cheapexpr(n, init) below leads to a recursive call
// to walkexpr, which leads us back here again. Use n.Opt to
// prevent infinite loops.
- if n.Opt() == &walkCheckPtrArithmeticMarker {
+ if opt := n.Opt(); opt == &walkCheckPtrArithmeticMarker {
return n
+ } else if opt != nil {
+ // We use n.Opt() here because today it's not used for OCONVNOP. If that changes,
+ // there's no guarantee that temporarily replacing it is safe, so just hard fail here.
+ Fatalf("unexpected Opt: %v", opt)
}
n.SetOpt(&walkCheckPtrArithmeticMarker)
defer n.SetOpt(nil)
--
cgit v1.3-5-g9baa
From 7067aa1c106d000e99b62e4804118c7bceeed680 Mon Sep 17 00:00:00 2001
From: Alex Brainman
Date: Sun, 27 Oct 2019 17:13:45 +1100
Subject: internal/syscall/windows/registry: make '-gcflags=all=-d=checkptr'
flag work
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Mostly replaced [:x] slice operation with [:x:x].
According to @mdempsky, compiler specially recognizes when you combine
a pointer conversion with a full slice operation in a single expression
and makes an exception.
Updates golang/go#34972
Change-Id: I07d9de3b31da254d55f50d14c18155f8fc8f3ece
Reviewed-on: https://go-review.googlesource.com/c/go/+/203442
Reviewed-by: Matthew Dempsky
Reviewed-by: Jason A. Donenfeld
---
src/internal/syscall/windows/registry/value.go | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/internal/syscall/windows/registry/value.go b/src/internal/syscall/windows/registry/value.go
index f8431d2c0f..bf8ab00759 100644
--- a/src/internal/syscall/windows/registry/value.go
+++ b/src/internal/syscall/windows/registry/value.go
@@ -108,7 +108,7 @@ func (k Key) GetStringValue(name string) (val string, valtype uint32, err error)
if len(data) == 0 {
return "", typ, nil
}
- u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
+ u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2]
return syscall.UTF16ToString(u), typ, nil
}
@@ -185,8 +185,7 @@ func ExpandString(value string) (string, error) {
return "", err
}
if n <= uint32(len(r)) {
- u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
- return syscall.UTF16ToString(u), nil
+ return syscall.UTF16ToString(r[:n]), nil
}
r = make([]uint16, n)
}
@@ -208,7 +207,7 @@ func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err err
if len(data) == 0 {
return nil, typ, nil
}
- p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
+ p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2]
if len(p) == 0 {
return nil, typ, nil
}
@@ -296,7 +295,7 @@ func (k Key) setStringValue(name string, valtype uint32, value string) error {
if err != nil {
return err
}
- buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+ buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2]
return k.setValue(name, valtype, buf)
}
@@ -326,7 +325,7 @@ func (k Key) SetStringsValue(name string, value []string) error {
ss += s + "\x00"
}
v := utf16.Encode([]rune(ss + "\x00"))
- buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+ buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2]
return k.setValue(name, MULTI_SZ, buf)
}
--
cgit v1.3-5-g9baa
From ac346a5fd99711e94996cae030cad1064da1daf2 Mon Sep 17 00:00:00 2001
From: Lynn Boger
Date: Mon, 28 Oct 2019 14:40:27 -0400
Subject: crypto/elliptic: clean up ppc64le implementation slightly
As suggested by comments from the review of CL 168478, this adds
Go code to do reverse bytes and removes the asm code, as well
as making a few cosmetic changes.
Change-Id: I08276a11222e03c3b42f4c9dc0d10a371a418be7
Reviewed-on: https://go-review.googlesource.com/c/go/+/203937
Run-TryBot: Lynn Boger
TryBot-Result: Gobot Gobot
Reviewed-by: Michael Munday
---
src/crypto/elliptic/p256_asm_ppc64le.s | 31 ++++---------------------------
src/crypto/elliptic/p256_ppc64le.go | 24 ++++++++++++++++++++----
2 files changed, 24 insertions(+), 31 deletions(-)
(limited to 'src')
diff --git a/src/crypto/elliptic/p256_asm_ppc64le.s b/src/crypto/elliptic/p256_asm_ppc64le.s
index 4428a18260..924e365c6c 100644
--- a/src/crypto/elliptic/p256_asm_ppc64le.s
+++ b/src/crypto/elliptic/p256_asm_ppc64le.s
@@ -105,10 +105,10 @@ GLOBL byteswap<>+0(SB), RODATA, $16
#define VMULT_LOW(x1, x2, out_low) \
VMULUWM x1, x2, out_low
- //
- // Vector multiply high word
- //
- // VMLHF x0, x1, out_hi
+//
+// Vector multiply high word
+//
+// VMLHF x0, x1, out_hi
#define VMULT_HI(x1, x2, out_hi) \
VMULEUW x1, x2, TMP1; \
VMULOUW x1, x2, TMP2; \
@@ -167,27 +167,6 @@ GLOBL byteswap<>+0(SB), RODATA, $16
#define res_ptr R3
#define a_ptr R4
-// func p256ReverseBytes(res, in []byte)
-// Reuse of target and destination OK
-TEXT ·p256ReverseBytes(SB), NOSPLIT, $0-48
- MOVD res+0(FP), res_ptr
- MOVD in+24(FP), a_ptr
-
- MOVD $8, R5
- MOVD $16, R6
- MOVD $24, R7
-
- MOVDBR (R0+a_ptr), R8
- MOVDBR (R5+a_ptr), R9
- MOVDBR (R6+a_ptr), R10
- MOVDBR (R7+a_ptr), R11
-
- MOVD R11, (R0+res_ptr)
- MOVD R10, (R5+res_ptr)
- MOVD R9, (R6+res_ptr)
- MOVD R8, (R7+res_ptr)
- RET
-
#undef res_ptr
#undef a_ptr
@@ -1624,8 +1603,6 @@ TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $16-48
VPERM X1, X1, SWAP, X1
CALL p256MulInternal<>(SB)
- // VST T1, 64(P3ptr)
- // VST T0, 80(P3ptr)
VOR T0, T0, Z3L
VOR T1, T1, Z3H
diff --git a/src/crypto/elliptic/p256_ppc64le.go b/src/crypto/elliptic/p256_ppc64le.go
index 4b41fb99af..160bdb12e3 100644
--- a/src/crypto/elliptic/p256_ppc64le.go
+++ b/src/crypto/elliptic/p256_ppc64le.go
@@ -8,6 +8,7 @@ package elliptic
import (
"crypto/subtle"
+ "encoding/binary"
"math/big"
)
@@ -77,10 +78,6 @@ func p256Select(point *p256Point, table []p256Point, idx int)
//go:noescape
func p256SelectBase(point *p256Point, table []p256Point, idx int)
-// Reverse the bytes (endianness)
-//go:noescape
-func p256ReverseBytes(res, in []byte)
-
// Point add with P2 being affine point
// If sign == 1 -> P2 = -P2
// If sel == 0 -> P3 = P1
@@ -145,6 +142,25 @@ func maybeReduceModP(in *big.Int) *big.Int {
return new(big.Int).Mod(in, p256Params.P)
}
+// p256ReverseBytes copies the first 32 bytes from in to res in reverse order.
+func p256ReverseBytes(res, in []byte) {
+ // remove bounds check
+ in = in[:32]
+ res = res[:32]
+
+ // Load in reverse order
+ a := binary.BigEndian.Uint64(in[0:])
+ b := binary.BigEndian.Uint64(in[8:])
+ c := binary.BigEndian.Uint64(in[16:])
+ d := binary.BigEndian.Uint64(in[24:])
+
+ // Store in normal order
+ binary.LittleEndian.PutUint64(res[0:], d)
+ binary.LittleEndian.PutUint64(res[8:], c)
+ binary.LittleEndian.PutUint64(res[16:], b)
+ binary.LittleEndian.PutUint64(res[24:], a)
+}
+
func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
var r1, r2 p256Point
--
cgit v1.3-5-g9baa
From b6bdf4587f7b58b78982553b7d10b73d0a381152 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Mon, 28 Oct 2019 22:14:04 -0400
Subject: runtime: unblock SIGUSR1 for TestPreemptM
TestPreemptM tests signal delivery using SIGUSR1, but (for unknown
reasons) SIGUSR1 is blocked by default on android/arm and
android/arm64, causing the test to fail.
This fixes the test by ensuring that SIGUSR1 is unblocked for this
test.
Updates #10958, #24543.
Change-Id: I9f81fbab53f96c74622aabcb6f5276f79e2b6d33
Reviewed-on: https://go-review.googlesource.com/c/go/+/203957
Run-TryBot: Austin Clements
Reviewed-by: Cherry Zhang
TryBot-Result: Gobot Gobot
---
src/runtime/export_unix_test.go | 6 ++++++
1 file changed, 6 insertions(+)
(limited to 'src')
diff --git a/src/runtime/export_unix_test.go b/src/runtime/export_unix_test.go
index 3f8bff619d..7af1c1dd54 100644
--- a/src/runtime/export_unix_test.go
+++ b/src/runtime/export_unix_test.go
@@ -33,6 +33,10 @@ var waitForSigusr1 struct {
// the ID of the M the SIGUSR1 was received on. If no SIGUSR1 is
// received for timeoutNS nanoseconds, it returns -1.
func WaitForSigusr1(ready func(mp *M), timeoutNS int64) (int64, int64) {
+ lockOSThread()
+ // Make sure we can receive SIGUSR1.
+ unblocksig(_SIGUSR1)
+
mp := getg().m
testSigusr1 = func(gp *g) bool {
waitForSigusr1.mp = gp.m
@@ -46,6 +50,8 @@ func WaitForSigusr1(ready func(mp *M), timeoutNS int64) (int64, int64) {
waitForSigusr1.mp = nil
testSigusr1 = nil
+ unlockOSThread()
+
if !ok {
return -1, -1
}
--
cgit v1.3-5-g9baa
From 28a15e3df34258f4f6c1de319fa30a81356ee92c Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Mon, 28 Oct 2019 22:19:32 -0400
Subject: runtime: rename TestPreemptM to TestSignalM
TestPreemptM doesn't test preemptM, it tests signalM. Rename it and
co-locate it with the other tests related to signals.
Change-Id: I7b95f2ba96530c49cfa8d5bf33282946b5f2d9af
Reviewed-on: https://go-review.googlesource.com/c/go/+/203891
Run-TryBot: Austin Clements
Reviewed-by: Brad Fitzpatrick
Reviewed-by: Cherry Zhang
TryBot-Result: Gobot Gobot
---
src/runtime/crash_unix_test.go | 24 ++++++++++++++++++++++++
src/runtime/preemptm_test.go | 35 -----------------------------------
2 files changed, 24 insertions(+), 35 deletions(-)
delete mode 100644 src/runtime/preemptm_test.go
(limited to 'src')
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
index 4be4962f90..93cee350d0 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -16,6 +16,7 @@ import (
"path/filepath"
"runtime"
"strings"
+ "sync"
"syscall"
"testing"
"unsafe"
@@ -309,3 +310,26 @@ func TestSignalDuringExec(t *testing.T) {
t.Fatalf("want %s, got %s\n", want, output)
}
}
+
+func TestSignalM(t *testing.T) {
+ var want, got int64
+ var wg sync.WaitGroup
+ ready := make(chan *runtime.M)
+ wg.Add(1)
+ go func() {
+ runtime.LockOSThread()
+ want, got = runtime.WaitForSigusr1(func(mp *runtime.M) {
+ ready <- mp
+ }, 1e9)
+ runtime.UnlockOSThread()
+ wg.Done()
+ }()
+ waitingM := <-ready
+ runtime.SendSigusr1(waitingM)
+ wg.Wait()
+ if got == -1 {
+ t.Fatal("signalM signal not received")
+ } else if want != got {
+ t.Fatalf("signal sent to M %d, but received on M %d", want, got)
+ }
+}
diff --git a/src/runtime/preemptm_test.go b/src/runtime/preemptm_test.go
deleted file mode 100644
index 70c6ad55cb..0000000000
--- a/src/runtime/preemptm_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
-
-package runtime_test
-
-import (
- "runtime"
- "sync"
- "testing"
-)
-
-func TestPreemptM(t *testing.T) {
- var want, got int64
- var wg sync.WaitGroup
- ready := make(chan *runtime.M)
- wg.Add(1)
- go func() {
- runtime.LockOSThread()
- want, got = runtime.WaitForSigusr1(func(mp *runtime.M) {
- ready <- mp
- }, 1e9)
- runtime.UnlockOSThread()
- wg.Done()
- }()
- runtime.SendSigusr1(<-ready)
- wg.Wait()
- if got == -1 {
- t.Fatal("preemptM signal not received")
- } else if want != got {
- t.Fatalf("signal sent to M %d, but received on M %d", want, got)
- }
-}
--
cgit v1.3-5-g9baa
From ec10e6f364dddef88223eb9ddda1ee900b1551cb Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Tue, 29 Oct 2019 00:16:28 -0400
Subject: cmd/compile: fix missing lowering of atomic {Load,Store}8
CL 203284 added a compiler intrinsics from atomic Load8 and Store8 on
several architectures, but missed the lowering on MIPS. This CL fixes
that.
Updates #10958, #24543.
Change-Id: I82e88971554fe8c33ad2bf195a633c44b9ac4cf7
Reviewed-on: https://go-review.googlesource.com/c/go/+/203977
Run-TryBot: Austin Clements
Reviewed-by: Cherry Zhang
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/mips/ssa.go | 24 ++++++++++---
src/cmd/compile/internal/ssa/gen/MIPS.rules | 10 +++---
src/cmd/compile/internal/ssa/gen/MIPSOps.go | 10 +++---
src/cmd/compile/internal/ssa/opGen.go | 35 ++++++++++++++++---
src/cmd/compile/internal/ssa/rewriteMIPS.go | 54 ++++++++++++++++++++++-------
5 files changed, 104 insertions(+), 29 deletions(-)
(limited to 'src')
diff --git a/src/cmd/compile/internal/mips/ssa.go b/src/cmd/compile/internal/mips/ssa.go
index bac8574b5c..7efd8e105b 100644
--- a/src/cmd/compile/internal/mips/ssa.go
+++ b/src/cmd/compile/internal/mips/ssa.go
@@ -497,20 +497,36 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Name = obj.NAME_EXTERN
p.To.Sym = gc.ExtendCheckFunc[v.AuxInt]
s.UseArgs(12) // space used in callee args area by assembly stubs
- case ssa.OpMIPSLoweredAtomicLoad:
+ case ssa.OpMIPSLoweredAtomicLoad8,
+ ssa.OpMIPSLoweredAtomicLoad32:
s.Prog(mips.ASYNC)
- p := s.Prog(mips.AMOVW)
+ var op obj.As
+ switch v.Op {
+ case ssa.OpMIPSLoweredAtomicLoad8:
+ op = mips.AMOVB
+ case ssa.OpMIPSLoweredAtomicLoad32:
+ op = mips.AMOVW
+ }
+ p := s.Prog(op)
p.From.Type = obj.TYPE_MEM
p.From.Reg = v.Args[0].Reg()
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg0()
s.Prog(mips.ASYNC)
- case ssa.OpMIPSLoweredAtomicStore:
+ case ssa.OpMIPSLoweredAtomicStore8,
+ ssa.OpMIPSLoweredAtomicStore32:
s.Prog(mips.ASYNC)
- p := s.Prog(mips.AMOVW)
+ var op obj.As
+ switch v.Op {
+ case ssa.OpMIPSLoweredAtomicStore8:
+ op = mips.AMOVB
+ case ssa.OpMIPSLoweredAtomicStore32:
+ op = mips.AMOVW
+ }
+ p := s.Prog(op)
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[1].Reg()
p.To.Type = obj.TYPE_MEM
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules
index 2932f13ac7..b6c5a9349d 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS.rules
+++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules
@@ -351,11 +351,11 @@
(InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
// atomic intrinsics
-(AtomicLoad32 ptr mem) -> (LoweredAtomicLoad ptr mem)
-(AtomicLoadPtr ptr mem) -> (LoweredAtomicLoad ptr mem)
+(AtomicLoad(8|32) ptr mem) -> (LoweredAtomicLoad(8|32) ptr mem)
+(AtomicLoadPtr ptr mem) -> (LoweredAtomicLoad32 ptr mem)
-(AtomicStore32 ptr val mem) -> (LoweredAtomicStore ptr val mem)
-(AtomicStorePtrNoWB ptr val mem) -> (LoweredAtomicStore ptr val mem)
+(AtomicStore(8|32) ptr val mem) -> (LoweredAtomicStore(8|32) ptr val mem)
+(AtomicStorePtrNoWB ptr val mem) -> (LoweredAtomicStore32 ptr val mem)
(AtomicExchange32 ptr val mem) -> (LoweredAtomicExchange ptr val mem)
(AtomicAdd32 ptr val mem) -> (LoweredAtomicAdd ptr val mem)
@@ -708,6 +708,6 @@
(CMOVZ a (MOVWconst [0]) c) -> (CMOVZzero a c)
// atomic
-(LoweredAtomicStore ptr (MOVWconst [0]) mem) -> (LoweredAtomicStorezero ptr mem)
+(LoweredAtomicStore32 ptr (MOVWconst [0]) mem) -> (LoweredAtomicStorezero ptr mem)
(LoweredAtomicAdd ptr (MOVWconst [c]) mem) && is16Bit(c) -> (LoweredAtomicAddconst [c] ptr mem)
diff --git a/src/cmd/compile/internal/ssa/gen/MIPSOps.go b/src/cmd/compile/internal/ssa/gen/MIPSOps.go
index 0f7b985e06..b82358b24a 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPSOps.go
+++ b/src/cmd/compile/internal/ssa/gen/MIPSOps.go
@@ -262,15 +262,17 @@ func init() {
// load from arg0. arg1=mem.
// returns so they can be properly ordered with other loads.
// SYNC
- // MOVW (Rarg0), Rout
+ // MOV(B|W) (Rarg0), Rout
// SYNC
- {name: "LoweredAtomicLoad", argLength: 2, reg: gpload, faultOnNilArg0: true},
+ {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
+ {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
// store arg1 to arg0. arg2=mem. returns memory.
// SYNC
- // MOVW Rarg1, (Rarg0)
+ // MOV(B|W) Rarg1, (Rarg0)
// SYNC
- {name: "LoweredAtomicStore", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
// atomic exchange.
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 5077e80a15..9f112c10f1 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -1537,8 +1537,10 @@ const (
OpMIPSCALLstatic
OpMIPSCALLclosure
OpMIPSCALLinter
- OpMIPSLoweredAtomicLoad
- OpMIPSLoweredAtomicStore
+ OpMIPSLoweredAtomicLoad8
+ OpMIPSLoweredAtomicLoad32
+ OpMIPSLoweredAtomicStore8
+ OpMIPSLoweredAtomicStore32
OpMIPSLoweredAtomicStorezero
OpMIPSLoweredAtomicExchange
OpMIPSLoweredAtomicAdd
@@ -20316,7 +20318,20 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "LoweredAtomicLoad",
+ name: "LoweredAtomicLoad8",
+ argLen: 2,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 R31
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicLoad32",
argLen: 2,
faultOnNilArg0: true,
reg: regInfo{
@@ -20329,7 +20344,19 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "LoweredAtomicStore",
+ name: "LoweredAtomicStore8",
+ argLen: 3,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31
+ {0, 140738025226238}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicStore32",
argLen: 3,
faultOnNilArg0: true,
hasSideEffects: true,
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go
index 72e596517f..d17be4422b 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go
@@ -41,12 +41,16 @@ func rewriteValueMIPS(v *Value) bool {
return rewriteValueMIPS_OpAtomicExchange32_0(v)
case OpAtomicLoad32:
return rewriteValueMIPS_OpAtomicLoad32_0(v)
+ case OpAtomicLoad8:
+ return rewriteValueMIPS_OpAtomicLoad8_0(v)
case OpAtomicLoadPtr:
return rewriteValueMIPS_OpAtomicLoadPtr_0(v)
case OpAtomicOr8:
return rewriteValueMIPS_OpAtomicOr8_0(v)
case OpAtomicStore32:
return rewriteValueMIPS_OpAtomicStore32_0(v)
+ case OpAtomicStore8:
+ return rewriteValueMIPS_OpAtomicStore8_0(v)
case OpAtomicStorePtrNoWB:
return rewriteValueMIPS_OpAtomicStorePtrNoWB_0(v)
case OpAvg32u:
@@ -245,8 +249,8 @@ func rewriteValueMIPS(v *Value) bool {
return rewriteValueMIPS_OpMIPSCMOVZzero_0(v)
case OpMIPSLoweredAtomicAdd:
return rewriteValueMIPS_OpMIPSLoweredAtomicAdd_0(v)
- case OpMIPSLoweredAtomicStore:
- return rewriteValueMIPS_OpMIPSLoweredAtomicStore_0(v)
+ case OpMIPSLoweredAtomicStore32:
+ return rewriteValueMIPS_OpMIPSLoweredAtomicStore32_0(v)
case OpMIPSMOVBUload:
return rewriteValueMIPS_OpMIPSMOVBUload_0(v)
case OpMIPSMOVBUreg:
@@ -826,11 +830,23 @@ func rewriteValueMIPS_OpAtomicExchange32_0(v *Value) bool {
}
func rewriteValueMIPS_OpAtomicLoad32_0(v *Value) bool {
// match: (AtomicLoad32 ptr mem)
- // result: (LoweredAtomicLoad ptr mem)
+ // result: (LoweredAtomicLoad32 ptr mem)
for {
mem := v.Args[1]
ptr := v.Args[0]
- v.reset(OpMIPSLoweredAtomicLoad)
+ v.reset(OpMIPSLoweredAtomicLoad32)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicLoad8_0(v *Value) bool {
+ // match: (AtomicLoad8 ptr mem)
+ // result: (LoweredAtomicLoad8 ptr mem)
+ for {
+ mem := v.Args[1]
+ ptr := v.Args[0]
+ v.reset(OpMIPSLoweredAtomicLoad8)
v.AddArg(ptr)
v.AddArg(mem)
return true
@@ -838,11 +854,11 @@ func rewriteValueMIPS_OpAtomicLoad32_0(v *Value) bool {
}
func rewriteValueMIPS_OpAtomicLoadPtr_0(v *Value) bool {
// match: (AtomicLoadPtr ptr mem)
- // result: (LoweredAtomicLoad ptr mem)
+ // result: (LoweredAtomicLoad32 ptr mem)
for {
mem := v.Args[1]
ptr := v.Args[0]
- v.reset(OpMIPSLoweredAtomicLoad)
+ v.reset(OpMIPSLoweredAtomicLoad32)
v.AddArg(ptr)
v.AddArg(mem)
return true
@@ -923,12 +939,26 @@ func rewriteValueMIPS_OpAtomicOr8_0(v *Value) bool {
}
func rewriteValueMIPS_OpAtomicStore32_0(v *Value) bool {
// match: (AtomicStore32 ptr val mem)
- // result: (LoweredAtomicStore ptr val mem)
+ // result: (LoweredAtomicStore32 ptr val mem)
+ for {
+ mem := v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ v.reset(OpMIPSLoweredAtomicStore32)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicStore8_0(v *Value) bool {
+ // match: (AtomicStore8 ptr val mem)
+ // result: (LoweredAtomicStore8 ptr val mem)
for {
mem := v.Args[2]
ptr := v.Args[0]
val := v.Args[1]
- v.reset(OpMIPSLoweredAtomicStore)
+ v.reset(OpMIPSLoweredAtomicStore8)
v.AddArg(ptr)
v.AddArg(val)
v.AddArg(mem)
@@ -937,12 +967,12 @@ func rewriteValueMIPS_OpAtomicStore32_0(v *Value) bool {
}
func rewriteValueMIPS_OpAtomicStorePtrNoWB_0(v *Value) bool {
// match: (AtomicStorePtrNoWB ptr val mem)
- // result: (LoweredAtomicStore ptr val mem)
+ // result: (LoweredAtomicStore32 ptr val mem)
for {
mem := v.Args[2]
ptr := v.Args[0]
val := v.Args[1]
- v.reset(OpMIPSLoweredAtomicStore)
+ v.reset(OpMIPSLoweredAtomicStore32)
v.AddArg(ptr)
v.AddArg(val)
v.AddArg(mem)
@@ -3000,8 +3030,8 @@ func rewriteValueMIPS_OpMIPSLoweredAtomicAdd_0(v *Value) bool {
}
return false
}
-func rewriteValueMIPS_OpMIPSLoweredAtomicStore_0(v *Value) bool {
- // match: (LoweredAtomicStore ptr (MOVWconst [0]) mem)
+func rewriteValueMIPS_OpMIPSLoweredAtomicStore32_0(v *Value) bool {
+ // match: (LoweredAtomicStore32 ptr (MOVWconst [0]) mem)
// result: (LoweredAtomicStorezero ptr mem)
for {
mem := v.Args[2]
--
cgit v1.3-5-g9baa
From a0c1e8d1ab07068e14b5abcd02099dbfb932188b Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor
Date: Tue, 29 Oct 2019 06:39:01 -0700
Subject: context: mark testDeadline as a testing helper method
Change-Id: Ie6fc3e9789aea6e5949e66186db6f2b071b6fdff
Reviewed-on: https://go-review.googlesource.com/c/go/+/204037
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/context/context_test.go | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/context/context_test.go b/src/context/context_test.go
index 869b02c92e..cff09fd322 100644
--- a/src/context/context_test.go
+++ b/src/context/context_test.go
@@ -253,6 +253,7 @@ func XTestChildFinishesFirst(t testingT) {
}
func testDeadline(c Context, name string, failAfter time.Duration, t testingT) {
+ t.Helper()
select {
case <-time.After(failAfter):
t.Fatalf("%s: context should have timed out", name)
--
cgit v1.3-5-g9baa
From e7ce8627b0adb0dfa8657c5186a1a53e1baad404 Mon Sep 17 00:00:00 2001
From: Than McIntosh
Date: Thu, 10 Oct 2019 12:11:06 -0400
Subject: cmd/compile: fix spurious R_TLE_LE reloc on android/386
When compiling for GOARCH=386 GOOS=android, the compiler was attaching
R_TLS_LE relocations inappropriately -- as of Go 1.13 the TLS access
recipe for Android refers to a runtime symbol and no longer needs this
type of relocation (which was causing a crash when the linker tried to
process it).
Updates #29674.
Fixes #34788.
Change-Id: Ida01875011b524586597b1f7e273aa14e11815d6
Reviewed-on: https://go-review.googlesource.com/c/go/+/200337
Run-TryBot: Than McIntosh
TryBot-Result: Gobot Gobot
Reviewed-by: Elias Naur
Reviewed-by: Cherry Zhang
---
src/cmd/internal/obj/x86/asm6.go | 2 +-
src/cmd/link/link_test.go | 61 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 618e88212c..3a33bc3c3c 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -3468,7 +3468,7 @@ func (ab *AsmBuf) asmandsz(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, a *obj
}
if REG_AX <= base && base <= REG_R15 {
- if a.Index == REG_TLS && !ctxt.Flag_shared {
+ if a.Index == REG_TLS && !ctxt.Flag_shared && !isAndroid {
rel = obj.Reloc{}
rel.Type = objabi.R_TLS_LE
rel.Siz = 4
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 29b98e9c32..155fd8bce3 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -1,6 +1,8 @@
package main
import (
+ "bufio"
+ "bytes"
"debug/macho"
"internal/testenv"
"io/ioutil"
@@ -315,3 +317,62 @@ func TestMacOSVersion(t *testing.T) {
t.Errorf("no LC_VERSION_MIN_MACOSX load command found")
}
}
+
+const Issue34788src = `
+
+package blah
+
+func Blah(i int) int {
+ a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
+ return a[i&7]
+}
+`
+
+func TestIssue34788Android386TLSSequence(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ // This is a cross-compilation test, so it doesn't make
+ // sense to run it on every GOOS/GOARCH combination. Limit
+ // the test to amd64 + darwin/linux.
+ if runtime.GOARCH != "amd64" ||
+ (runtime.GOOS != "darwin" && runtime.GOOS != "linux") {
+ t.Skip("skipping on non-{linux,darwin}/amd64 platform")
+ }
+
+ tmpdir, err := ioutil.TempDir("", "TestIssue34788Android386TLSSequence")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ src := filepath.Join(tmpdir, "blah.go")
+ err = ioutil.WriteFile(src, []byte(Issue34788src), 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ obj := filepath.Join(tmpdir, "blah.o")
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", obj, src)
+ cmd.Env = append(os.Environ(), "GOARCH=386", "GOOS=android")
+ if out, err := cmd.CombinedOutput(); err != nil {
+ if err != nil {
+ t.Fatalf("failed to compile blah.go: %v, output: %s\n", err, out)
+ }
+ }
+
+ // Run objdump on the resulting object.
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "objdump", obj)
+ out, oerr := cmd.CombinedOutput()
+ if oerr != nil {
+ t.Fatalf("failed to objdump blah.o: %v, output: %s\n", oerr, out)
+ }
+
+ // Sift through the output; we should not be seeing any R_TLS_LE relocs.
+ scanner := bufio.NewScanner(bytes.NewReader(out))
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.Contains(line, "R_TLS_LE") {
+ t.Errorf("objdump output contains unexpected R_TLS_LE reloc: %s", line)
+ }
+ }
+}
--
cgit v1.3-5-g9baa
From 1a058cd04b7b902e59ff5584c7fda8ddfe388981 Mon Sep 17 00:00:00 2001
From: Michael Fraenkel
Date: Fri, 18 Oct 2019 22:19:59 -0400
Subject: net/http: only decrement connection count if we removed a connection
The connection count must only be decremented if the persistent
connection was also removed.
Fixes #34941
Change-Id: I5070717d5d9effec78016005fa4910593500c8cf
Reviewed-on: https://go-review.googlesource.com/c/go/+/202087
Reviewed-by: Brad Fitzpatrick
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/net/http/transport.go | 15 +++++++----
src/net/http/transport_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+), 5 deletions(-)
(limited to 'src')
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index c2880a04cf..8989f65f25 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -545,8 +545,9 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
_, isH2DialError := pconn.alt.(http2erringRoundTripper)
if http2isNoCachedConnError(err) || isH2DialError {
- t.removeIdleConn(pconn)
- t.decConnsPerHost(pconn.cacheKey)
+ if t.removeIdleConn(pconn) {
+ t.decConnsPerHost(pconn.cacheKey)
+ }
}
if !pconn.shouldRetryRequest(req, err) {
// Issue 16465: return underlying net.Conn.Read error from peek,
@@ -958,26 +959,28 @@ func (t *Transport) queueForIdleConn(w *wantConn) (delivered bool) {
}
// removeIdleConn marks pconn as dead.
-func (t *Transport) removeIdleConn(pconn *persistConn) {
+func (t *Transport) removeIdleConn(pconn *persistConn) bool {
t.idleMu.Lock()
defer t.idleMu.Unlock()
- t.removeIdleConnLocked(pconn)
+ return t.removeIdleConnLocked(pconn)
}
// t.idleMu must be held.
-func (t *Transport) removeIdleConnLocked(pconn *persistConn) {
+func (t *Transport) removeIdleConnLocked(pconn *persistConn) bool {
if pconn.idleTimer != nil {
pconn.idleTimer.Stop()
}
t.idleLRU.remove(pconn)
key := pconn.cacheKey
pconns := t.idleConn[key]
+ var removed bool
switch len(pconns) {
case 0:
// Nothing
case 1:
if pconns[0] == pconn {
delete(t.idleConn, key)
+ removed = true
}
default:
for i, v := range pconns {
@@ -988,9 +991,11 @@ func (t *Transport) removeIdleConnLocked(pconn *persistConn) {
// conns at the end.
copy(pconns[i:], pconns[i+1:])
t.idleConn[key] = pconns[:len(pconns)-1]
+ removed = true
break
}
}
+ return removed
}
func (t *Transport) setReqCanceler(r *Request, fn func(error)) {
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 3673ed29f0..0d63e46d4f 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -5893,3 +5893,59 @@ func TestDontCacheBrokenHTTP2Conn(t *testing.T) {
t.Errorf("GotConn calls = %v; want %v", got, want)
}
}
+
+// Issue 34941
+// When the client has too many concurrent requests on a single connection,
+// http.http2noCachedConnError is reported on multiple requests. There should
+// only be one decrement regardless of the number of failures.
+func TestTransportDecrementConnWhenIdleConnRemoved(t *testing.T) {
+ defer afterTest(t)
+
+ h := HandlerFunc(func(w ResponseWriter, r *Request) {
+ _, err := w.Write([]byte("foo"))
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ })
+
+ ts := httptest.NewUnstartedServer(h)
+ ts.EnableHTTP2 = true
+ ts.StartTLS()
+ defer ts.Close()
+
+ c := ts.Client()
+ tr := c.Transport.(*Transport)
+ tr.MaxConnsPerHost = 1
+ if err := ExportHttp2ConfigureTransport(tr); err != nil {
+ t.Fatalf("ExportHttp2ConfigureTransport: %v", err)
+ }
+
+ errCh := make(chan error, 300)
+ doReq := func() {
+ resp, err := c.Get(ts.URL)
+ if err != nil {
+ errCh <- fmt.Errorf("request failed: %v", err)
+ return
+ }
+ defer resp.Body.Close()
+ _, err = ioutil.ReadAll(resp.Body)
+ if err != nil {
+ errCh <- fmt.Errorf("read body failed: %v", err)
+ }
+ }
+
+ var wg sync.WaitGroup
+ for i := 0; i < 300; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ doReq()
+ }()
+ }
+ wg.Wait()
+ close(errCh)
+
+ for err := range errCh {
+ t.Errorf("error occurred: %v", err)
+ }
+}
--
cgit v1.3-5-g9baa
From 64533374941d238c542167d67711a66ebac4ef67 Mon Sep 17 00:00:00 2001
From: Clément Chigot