aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/sys_windows_amd64.s
AgeCommit message (Collapse)Author
2025-12-08[dev.simd] cmd/compile: zero only low 128-bit of X15Cherry Mui
Zeroing the upper part of X15 may make the CPU think it is "dirty" and slow down SSE operations. For now, just not zeroing the upper part, and construct a zero value on the fly if we need a 256- or 512-bit zero value. Maybe VZEROUPPER works better than explicitly zeroing X15, but we need to evaluate. Long term, we probably want to move more things from SSE to AVX. This essentially undoes CL 698237 and CL 698238, except keeping using X15 for 128-bit zeroing for SIMD. Change-Id: I1564e6332c4c57f9721397c92c7c734c5497534c Reviewed-on: https://go-review.googlesource.com/c/go/+/728240 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com>
2025-11-26cmd/compile, runtime: guard X15 zeroing with GOEXPERIMENT=simdCherry Mui
If simd experiment is not enabled, the compiler doesn't use the AVX part of the register. So only zero it with the SSE instruction. Change-Id: Ia3bdf34a9ed273128db2ee0f4f5db6f7cc76a975 Reviewed-on: https://go-review.googlesource.com/c/go/+/724720 Reviewed-by: Junyang Shao <shaojunyang@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com>
2025-08-22[dev.simd] cmd/compile: ensure the whole X15 register is zeroedCherry Mui
On AMD64, we reserve the X15 register as the zero register. Currently we use an SSE instruction to zero it, and we only use it in SSE contexts. When the machine supports AVX, the high bits of the register is not necessarily zeroed. Now that the compiler generates AVX code for SIMD, it would be great to have a zero register in the AVX context. This CL zeroes the whole X15 register if AVX is supported. Change-Id: I4dc803362f2e007b1614b90de435fbb7814cebc7 Reviewed-on: https://go-review.googlesource.com/c/go/+/698237 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Junyang Shao <shaojunyang@google.com> Reviewed-by: David Chase <drchase@google.com>
2025-07-28internal/runtime/syscall/windows: factor out code from runtimeqmuntal
Factor out the code related to doing calls using the Windows stdcall calling convention into a separate package. This will allow us to reuse it in other low-level packages that can't depend on syscall. Updates #51087. Cq-Include-Trybots: luci.golang.try:gotip-windows-arm64,gotip-windows-amd64-longtest,gotip-solaris-amd64 Change-Id: I68640b07091183b50da6bef17406c10a397896e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/689156 Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2024-02-19runtime: use the right number of parameters in syscall_SyscallX on Windowsqmuntal
The syscall_SyscallX functions currently discard the nargs parameter when calling syscall_SyscallN. This precludes some optimizations down the line. For example, on amd64, a syscall that takes 0 arguments don't need to set any of the params passing registers (CX, DX, R8, and R9). This CL updates all syscall_SyscallX functions so they call syscall_SyscallN with an argument slice of the right length. While here, remove the hack in syscall_SyscallN to support less than 4 arguments, and update instead asmstdcall on amd64 to properly handle this case. Change-Id: I0328e14f34c2b000fde06cc6a579b09e8c32f2b9 Reviewed-on: https://go-review.googlesource.com/c/go/+/563315 TryBot-Result: Gopher Robot <gobot@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Than McIntosh <thanm@google.com>
2023-10-05runtime: support SetUnhandledExceptionFilter on Windowsqmuntal
The Windows unhandled exception mechanism fails to call the callback set in SetUnhandledExceptionFilter if the stack can't be correctly unwound. Some cgo glue code was not properly chaining the frame pointer, making the stack unwind to fail in case of an exception inside a cgo call. This CL fix that and adds a test case to avoid regressions. Fixes #50951 Change-Id: Ic782b5257fe90b05e3def8dbf0bb8d4ed37a190b Reviewed-on: https://go-review.googlesource.com/c/go/+/525475 Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> TryBot-Result: Gopher Robot <gobot@golang.org>
2023-09-21runtime: implement usleep in Go instead of assembly on Windowsqmuntal
Windows APIs are normally not arch-specific, so it's better to implement them in Go instead of assembly. It was previously implemented in assembly because it was the only way to support calls without a valid g. This CL defines a new function, stdcall_no_g, that can be used in such cases. While here, I've also replaced the use of the deprecated syscall NtWaitForSingleObject with WaitForSingleObject. The former may give the illusion of being more accurate, as it takes a higher resolution timeout, but it's not. Windows time resolution is 15.6ms, and can be as high as 1ms when using a high resolution timer, which WaitForSingleObject supports. Change-Id: I903400220ade4d4ccc15685c8da47182430f8686 Reviewed-on: https://go-review.googlesource.com/c/go/+/526477 Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com>
2023-09-20runtime: implement osyield in Go instead of assembly on Windowsqmuntal
Windows APIs are normally not arch-specific, so it's better to implement them in Go instead of assembly. It was previously implemented in assembly because it was the only way to support calls without a valid g. This CL defines a new function, stdcall_no_g, that can be used in such cases. Change-Id: I26a223b918c6c462b06ac256bdacf9ddb78752bc Reviewed-on: https://go-review.googlesource.com/c/go/+/526476 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Bryan Mills <bcmills@google.com>
2023-09-12all: fix Microsoft linksqmuntal
This CL fixes the links to Microsoft documentation in the Go source code. Some links were broken and some others were outdated. Change-Id: I4c3bcd3aa3c07a31be1b7f94c25339dcc2e771e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/527556 Reviewed-by: Heschi Kreinick <heschi@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Auto-Submit: Quim Muntal <quimmuntal@gmail.com>
2023-09-07runtime: support nil libcall.args when calling stdcall on Windowsqmuntal
Having to pass a dummy pointer to the libcall.args field is a bit annoying. This change allows nil to be passed instead. windows/arm and windows/arm64 already support nil libcall.args. Change-Id: I07a2bdb7d1f76b13d125397ff5177337c43536a3 Reviewed-on: https://go-review.googlesource.com/c/go/+/526016 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Bryan Mills <bcmills@google.com>
2023-09-07runtime: remove slow time compatibility hacks for wineqmuntal
This reapplies CL 191759, which was reverted in CL 192622. Wine fixed the compatibility issue more than 3 years ago, in version 5.10 (see [1]). We no longer have to keep the compatibility hack on our side. Updates #34021 [1]: https://github.com/wine-mirror/wine/commit/1ae10889647c1c84c36660749508a42e99e64a5e Change-Id: I3b77701d01fdf58fbf350321fc0a957c0f247d32 Reviewed-on: https://go-review.googlesource.com/c/go/+/526358 Reviewed-by: Daniel Martí <mvdan@mvdan.cc> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2023-04-25runtime: fallback to TEB arbitrary pointer when TLS slots are fullqmuntal
The Go runtime allocates the TLS slot in the TEB TLS slots instead of using the TEB arbitrary pointer. See CL 431775 for more context. The problem is that the TEB TLS slots array only has capacity for 64 indices, allocating more requires some complex logic that we don't support yet. Although the Go runtime only allocates one index, a Go DLL can be loaded in a process with more than 64 TLS slots allocated, in which case it abort. This CL avoids aborting by falling back to the older behavior, that is to use the TEB arbitrary pointer. Fixes #59213 Change-Id: I39c73286fe2da95aa9c5ec5657ee0979ecbec533 Reviewed-on: https://go-review.googlesource.com/c/go/+/486816 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> TryBot-Result: Gopher Robot <gobot@golang.org>
2023-04-21runtime: tidy _Stack* constant namingAustin Clements
For #59670. Change-Id: I0efa743edc08e48dc8d906803ba45e9f641369db Reviewed-on: https://go-review.googlesource.com/c/go/+/486977 Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com>
2023-04-20Revert "runtime: tidy _Stack* constant naming"Austin Clements
This reverts commit CL 486381. Submitted out of order and breaks bootstrap. Change-Id: Ia472111cb966e884a48f8ee3893b3bf4b4f4f875 Reviewed-on: https://go-review.googlesource.com/c/go/+/486915 Reviewed-by: David Chase <drchase@google.com> TryBot-Bypass: Austin Clements <austin@google.com>
2023-04-20runtime: tidy _Stack* constant namingAustin Clements
For #59670. Change-Id: I4476d6f92663e8a825d063d6e6a7fc9a2ac99d4d Reviewed-on: https://go-review.googlesource.com/c/go/+/486381 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
2023-03-23all: replace leading spaces with tabs in assemblyMichael Pratt
Most of these are one-off mistakes. Only one file was all spaces. Change-Id: I277c3ce4a4811aa4248c90676f66bc775ae8d062 Reviewed-on: https://go-review.googlesource.com/c/go/+/478976 Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
2023-03-13runtime: implement high resolution timer on windows arm/arm64qmuntal
This CL moves the usleep2HighRes from assembly to good old Go. This is safe because since CL 288793 usleep is always called with a g, else one wold have to call usleep_no_g. This condition was not enforced when high resolution timers were first implemented on Windows (CL 248699), so the implementation was done in assembly. Other than removing a bunch of obscure assembly code, this CL makes high resolution timers work on windows arm/arm64 by free, as the system calls are the same in all windows platforms. Change-Id: I41ecf78026fd7e11e85258a411ae074a77e8c7fc Reviewed-on: https://go-review.googlesource.com/c/go/+/471142 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> Auto-Submit: Michael Pratt <mpratt@google.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com>
2023-03-01runtime: remove unnecessary NOFRAME flags on windowsqmuntal
This CL removes some NOFRAME flags on Windows assembly files for several reasons: - windows/386 does not use a frame pointer - Leaf frameless functions already skip the frame pointer - Some non-leaf functions do not contain enough dragons to justify not using the frame pointer Updates #58378 Change-Id: I31e71bf7f769e1957a4adba91778da5af66ce1e4 Reviewed-on: https://go-review.googlesource.com/c/go/+/466835 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
2023-01-25runtime: delete unused cbctxts variable on windows assemblyqmuntal
runtime·cbctxts has been unused since CL 258938, but it was left over. Change-Id: I374ad26e668a36994e41f5d17593b33090bdc644 Reviewed-on: https://go-review.googlesource.com/c/go/+/463119 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
2023-01-24runtime: use explicit NOFRAME on windows/amd64qmuntal
This CL marks non-leaf nosplit assembly functions as NOFRAME to avoid relying on the implicit amd64 NOFRAME heuristic, where NOSPLIT functions without stack were also marked as NOFRAME. Updates #57302 Updates #40044 Change-Id: Ia4d26f8420dcf2b54528969ffbf40a73f1315d61 Reviewed-on: https://go-review.googlesource.com/c/go/+/459395 Reviewed-by: Cherry Mui <cherryyz@google.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2023-01-24runtime: remove unused badsignal2 on windowsqmuntal
This CL removes badsignal2 function, as it is unused on Windows. badsignal2 was originally intended to abort the process when an exception was raised on a non-Go thread, following the same approach as Linux and others. Since it was added, back on https://golang.org/cl/5797068, it has caused several issues on Windows, see #8224 and #50877. That's because we can't know wether the signal is bad or not, as our trap might not be at the end of the exception handler chain. To fix those issues, https://golang.org/cl/104200046 and CL 442896 stopped calling badsignal2, and CL 458135 removed one last incorrect call on amd64 and 386. Change-Id: I5bd31ee2672118ae0f1a2c8b46a1bb0f4893a011 Reviewed-on: https://go-review.googlesource.com/c/go/+/463116 Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
2023-01-24runtime: factor out windows sigtrampqmuntal
This CL factors out part of the Windows sigtramp implementation, which was duplicated in all four architectures. The new common code is implemented in Go rather than in assembly, which will make Windows error handling easier to reason and maintain. While here, implement the control flow guard workaround on windows/386, which almost comes for free. Change-Id: I0bf38c28c54793225126e161bd95527a62de05e0 Reviewed-on: https://go-review.googlesource.com/c/go/+/458135 Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
2022-11-14runtime,cmd/internal/obj/x86: use TEB TLS slots on windows/amd64qmuntal
This CL redesign how we get the TLS pointer on windows/amd64. We were previously reading it from the [TEB] arbitrary data slot, located at 0x28(GS), which can only hold 1 TLS pointer. With this CL, we will read the TLS pointer from the TEB TLS slot array, located at 0x1480(GS). The TLS slot array can hold multiple TLS pointers, up to 64, so multiple Go runtimes running on the same thread can coexists with different TLS. Each new TLS slot has to be allocated via [TlsAlloc], which returns the slot index. This index can then be used to get the slot offset from GS with the following formula: 0x1480 + index*8 The slot index is fixed per Go runtime, so we can store it in runtime.tls_g and use it latter on to read/update the TLS pointer. Loading the TLS pointer requires the following asm instructions: MOVQ runtime.tls_g, AX MOVQ AX(GS), AX Notice that this approach is also implemented on windows/arm64. [TEB]: https://en.wikipedia.org/wiki/Win32_Thread_Information_Block [TlsAlloc]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-tlsalloc Updates #22192 Change-Id: Idea7119fd76a3cd083979a4d57ed64b552fa101b Reviewed-on: https://go-review.googlesource.com/c/go/+/431775 Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
2022-11-03runtime: support control flow guard on windows/amd64qmuntal
The stack pointer must lie within system stack limits when Control Flow Guard (CFG) is enabled on Windows. This CL updates runtime.sigtramp to honor this restriction by porting some code from the windows/arm64 version, which already supports CFG. Fixes #53560 Change-Id: I7f88f9ae788b2bac38aac898b2567f1bea62f8f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/437559 Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com> Run-TryBot: Michael Pratt <mpratt@google.com>
2021-11-03runtime: on windows, read nanotime with one instruction or issue barrierJason A. Donenfeld
On 64-bit, this is more efficient, and on ARM64, this prevents the time from moving backwards due to the weaker memory model. On ARM32 due to the weaker memory model, we issue a memory barrier. Updates #48072. Change-Id: If4695716c3039d8af14e14808af217f5c99fc93a Reviewed-on: https://go-review.googlesource.com/c/go/+/361057 Trust: Jason A. Donenfeld <Jason@zx2c4.com> Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2021-08-19syscall: add SyscallNChangkun Ou
This CL adds a new syscall.SyscallN API. The proposal discussion also suggests the API should not only for Windows but other platforms. However, the existing API set already contain differences between platforms, hence the CL only implements the Windows platform. Moreover, although the API offers variadic parameters, the permitted parameters remains up to a limit, which is selected as 42, and arguably large enough. Fixes #46552 Change-Id: I66b49988a304d9fc178c7cd5de46d0b75e167a4f Reviewed-on: https://go-review.googlesource.com/c/go/+/336550 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Trust: Matthew Dempsky <mdempsky@google.com> Trust: Jason A. Donenfeld <Jason@zx2c4.com>
2021-05-21[dev.typeparams] runtime: use internal/abi.FuncPCABI0 to take address of ↵Cherry Mui
assembly functions There are a few assembly functions in the runtime that are marked as ABIInternal, solely because funcPC can get the right address. The functions themselves do not actually follow ABIInternal (or irrelevant). Now we have internal/abi.FuncPCABI0, use that, and un-mark the functions. Also un-mark assembly functions that are only called in assembly. For them, it only matters if the caller and callee are consistent. Change-Id: I240e126ac13cb362f61ff8482057ee9f53c24097 Reviewed-on: https://go-review.googlesource.com/c/go/+/321950 Trust: Cherry Mui <cherryyz@google.com> Run-TryBot: Cherry Mui <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-05-04runtime: abort when receiving a signal on a non-Go thread on WindowsMichael Anthony Knyszek
Currently if a signal lands on a non-Go thread that's handled by the Go handler, Go will emit a message. However, unlike everywhere else in the runtime, Go will not abort the process after, and the signal handler will try to continue executing. This leads to cascading failures and possibly even memory corruption. For #45638. Change-Id: I546f4e82f339d555bed295528d819ac883b92bc6 Reviewed-on: https://go-review.googlesource.com/c/go/+/316809 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2021-04-28runtime: move Windows time.now implementations into separate filesIan Lance Taylor
This is a step toward separating whether time.now is implemented in assembly from whether we are using faketime. Change-Id: I8bf059b44a103b034835e3d3b799319cc05e9552 Reviewed-on: https://go-review.googlesource.com/c/go/+/314273 Trust: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-04-28runtime: consolidate Windows time constants into single copyIan Lance Taylor
Change-Id: I1a583d3da9cca4ac51f3fec9b508b7638b452d60 Reviewed-on: https://go-review.googlesource.com/c/go/+/314270 Trust: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-04-26runtime: fix offset in commentCherry Zhang
Change-Id: I2770195cb53220948081a6265f891ef064e4f763 Reviewed-on: https://go-review.googlesource.com/c/go/+/313629 Trust: Cherry Zhang <cherryyz@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-04-21runtime: call nanotimeQPC from nanotime1 normallyMichael Anthony Knyszek
Currently we call runtimeQPC as ABIInternal because it shaves off 24 bytes by not having an extra wrapper, and at the time we were exceeding the nosplit stack limit in some cases. However, this code was written before we had the regabiargs GOEXPERIMENT flag, and wasn't properly flagged. Naturally, with regabiargs enabled, it leads to garbage being returned, because it needs to store runtimeQPC's result to the stack. We didn't notice this because today runtimeQPC is only used in Wine, not on any native Windows platform. Back when I wrote this code, it appeared to be necessary on even native Windows, but it turns out that's not true anymore. Turn it back into a native call through a wrapper. For #40724. Change-Id: Ia2e5901965ef46c5f299daccef49952026854fe6 Reviewed-on: https://go-review.googlesource.com/c/go/+/312429 Trust: Michael Knyszek <mknyszek@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-04-15runtime,runtime/cgo: save all necessary registers on entry to Go on WindowsAustin Clements
There are several assembly functions that transition from the Windows ABI to the Go ABI. These all need to save all registers that are callee-save in the Windows ABI and caller-save in the Go ABI and prepare the register state for Go. However, they all do this slightly differently and most of them don't save the necessary XMM registers for this transition (which could corrupt them in the C caller). Furthermore, now that we have a carefully specified Go ABI, it's clear that none of these actually get all of the details 100% right. So, unify this code into two macros in a shared header in runtime/cgo/abi_amd64.h that handle all necessary registers and setup and use these macros everywhere on Windows that handles transitions from C to Go. Change-Id: I62f41345a507aad1ca383814ac8b7e2a9ffb821e Reviewed-on: https://go-review.googlesource.com/c/go/+/309769 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-04-14runtime: increase maxargs to avoid syscall18 crash when called with more ↵El Mostafa Idrassi
than 16 args Fixes #45524 Change-Id: Id867f45ea98689b73d5b1b141c19317bc7608b05 GitHub-Last-Rev: e9b09fb557dda291fb6cf27c185063c26832a15b GitHub-Pull-Request: golang/go#45531 Reviewed-on: https://go-review.googlesource.com/c/go/+/309390 Reviewed-by: El Mostafa Idrassi <el.mostafa.idrassi@gmail.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Trust: Alex Brainman <alex.brainman@gmail.com> Trust: Alberto Donizetti <alb.donizetti@gmail.com> Run-TryBot: Alex Brainman <alex.brainman@gmail.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-04-13runtime: eliminate externalthreadhandlerAustin Clements
This function is no longer used. Eliminating this actually fixes several problems: - It made assumptions about what registers memclrNoHeapPointers would preserve. Besides being an abstraction violation and lurking maintenance issue, this actively became a problem for regabi because the call to memclrNoHeapPointers now happens through an ABI wrapper, which is generated by the compiler and hence we can't easily control what registers it clobbers. - The amd64 implementation (at least), does not interact with the host ABI correctly. Notably, it doesn't save many of the registers that are callee-save in the host ABI but caller-save in the Go ABI. - It interacts strangely with the NOSPLIT checker because it allocates an entire M and G on its stack. It worked around this on arm64, and happened to do things the NOSPLIT checker couldn't track on 386 and amd64, and happened to be *4 bytes* below the limit on arm (so any addition to the m or g structs would cause a NOSPLIT failure). See CL 309031 for a more complete explanation. Fixes #45530. Updates #40724. Change-Id: Ic70d4d7e1c17f1d796575b3377b8529449e93576 Reviewed-on: https://go-review.googlesource.com/c/go/+/309634 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-04-13runtime: use newm for profileloopAustin Clements
This replaces the externalthreadhandler-based implementation of profileloop with one that uses newm to start a new thread. This is a step toward eliminating externalthreadhandler. For #45530. Change-Id: Id8e5540423fe2d2004024b649afec6998f77b092 Reviewed-on: https://go-review.googlesource.com/c/go/+/309633 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-04-13runtime: use compileCallback for ctrlhandlerAustin Clements
This replaces the externalthreadhandler-based implementation of ctrlhandler with one based on compileCallback. This is a step toward eliminating externalthreadhandler. For #45530. Change-Id: I2de2f2f37777af292db67ccf8057b7566aab81f8 Reviewed-on: https://go-review.googlesource.com/c/go/+/309632 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-04-12runtime: replace outdated documentation link in Windows' nanotimePaschalis Tsilias
Fixes #45498 Change-Id: I89365f3517bc84376f0f580c64a57f38aaba0cbb Reviewed-on: https://go-review.googlesource.com/c/go/+/308997 Reviewed-by: Ian Lance Taylor <iant@golang.org> Trust: Alex Brainman <alex.brainman@gmail.com>
2021-04-01runtime: fix uses of ABIInternal PCs in assemblyAustin Clements
The covers three kinds of uses: 1. Calls of closures from assembly. These are always ABIInternal calls without wrappers. I went through every indirect call in the runtime and I think mcall is the only case of assembly calling a Go closure in a way that's affected by ABIInternal. systemstack also calls a closure, but it takes no arguments. 2. Calls of Go functions that expect raw ABIInternal pointers. I also only found one of these: callbackasm1 -> cgocallback on Windows. These are trickier to find, though. 3. Finally, I found one case on NetBSD where new OS threads were directly calling the Go runtime entry-point from assembly via a PC, rather than going through a wrapper. This meant new threads may not have special registers set up. In this case, a change on all other OSes had already forced new thread entry to go through an ABI wrapper, so I just caught NetBSD up with that change. With this change, I'm able to run a "hello world" with GOEXPERIMENT=regabi,regabiargs. For #40724. Change-Id: I2a6d0e530c4fd4edf13484d923891c6160d683aa Reviewed-on: https://go-review.googlesource.com/c/go/+/305669 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-24runtime: bypass ABI wrapper when calling needm on WindowsMichael Anthony Knyszek
On Windows, when calling into needm in cgocallback on a new thread that is unknown to the Go runtime, we currently call through an ABI wrapper. The ABI wrapper tries to restore the G register from TLS. On other platforms, TLS is set up just enough that the wrapper will simply load a nil g from TLS, but on Windows TLS isn't set up at all, so there's nowhere for the wrapper to load from. So, bypass the wrapper in the call to needm. needm takes no arguments and returns no results so there are no special ABI considerations, except that we must clear X15 which is used as a zero register in Go code (a function normally performed by the ABI wrapper). needm is also otherwise already special and carefully crafted to avoid doing anything that would require a valid G or M, at least until it is able to create one. While we're here, this change simplifies setg so that it doesn't set up TLS on Windows and instead provides an OS-specific osSetupTLS to do that. The result of this is that setg(nil) no longer clears the TLS space pointer on Windows. There's exactly one place this is used (dropm) where it doesn't matter anymore, and an empty TLS means that setg's wrapper will crash on the return path. Another result is that the G slot in the TLS will be properly cleared, however, which isn't true today. For #40724. Change-Id: I65c3d924a3b16abe667b06fd91d467d6d5da31d7 Reviewed-on: https://go-review.googlesource.com/c/go/+/303070 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2021-03-19runtime: mark Windows' address-taken asm routines as ABIInternalMichael Anthony Knyszek
In the runtime there are Windows-specific assembly routines that are address-taken via funcPC and are not intended to be called through a wrapper. Mark them as ABIInternal so that we don't grab the wrapper, because that will break in all sorts of contexts. For #40724. For #44065. Change-Id: I12a728786786f423e5b229f8622e4a80ec27a31c Reviewed-on: https://go-review.googlesource.com/c/go/+/302109 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2021-03-19runtime: call nanotimeQPC from nanotime1 without a wrapperMichael Anthony Knyszek
This changes makes it so that nanotimeQPC calls nanotime1 without an ABI wrapper by specifying the ABIInternal version directly. The reason why this is necessary is because ABI wrappers typically require additional stack space, and nanotimeQPC is used deep within nosplit contexts, and with the ABI wrappers now enabled, this exhausts the stack guard space held for nosplit functions. Rather than increase the stack guard, we choose to do this. For #40724. Change-Id: Ia9173ca903335a9d6f380f57f4a45e49b58da6bb Reviewed-on: https://go-review.googlesource.com/c/go/+/303069 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2021-02-19runtime: use TOPFRAME to identify top-of-frame functionsRuss Cox
No change to actual runtime, but helps reduce the laundry list of functions. mcall, morestack, and asmcgocall are not actually top-of-frame, so those need more attention in follow-up CLs. mstart moved to assembly so that it can be marked TOPFRAME. Since TOPFRAME also tells DWARF consumers not to unwind this way, this change should also improve debuggers a marginal amount. This CL is part of a stack adding windows/arm64 support (#36439), intended to land in the Go 1.17 cycle. This CL is, however, not windows/arm64-specific. It is cleanup meant to make the port (and future ports) easier. Change-Id: If1e0d46ca973de5e46b62948d076f675f285b5d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/288802 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2021-02-19runtime: unify asmcgocall and systemstack traceback setupRuss Cox
Both asmcgocall and systemstack need to save the calling Go code's context for use by traceback, but they do it differently. Systemstack's appraoch is better, because it doesn't require a special case in traceback. So make them both use that. While we are here, the fake mstart caller in systemstack is no longer needed and can be removed. (traceback knows to stop in systemstack because of the writes to SP.) Also remove the fake mstarts in sys_windows_*.s. And while we are there, fix the control flow guard code in sys_windows_arm.s. The current code is using pointers to a stack frame that technically is gone once we hit the RET instruction. Clearly it's working OK, but better not to depend on data below SP being preserved, even for just a few instructions. Store the value we need in other registers instead. (This code is only used for pushing a sigpanic call, which does not actually return to the site of the fault and therefore doesn't need to preserve any of the registers.) This CL is part of a stack adding windows/arm64 support (#36439), intended to land in the Go 1.17 cycle. This CL is, however, not windows/arm64-specific. It is cleanup meant to make the port (and future ports) easier. Change-Id: Id1e3ef5e54f7ad786e4b87043f2626eba7c3bbd9 Reviewed-on: https://go-review.googlesource.com/c/go/+/288799 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2021-02-19runtime: delete windows setlasterror (unused)Russ Cox
This is dead code and need not be ported to each architecture. This CL is part of a stack adding windows/arm64 support (#36439), intended to land in the Go 1.17 cycle. This CL is, however, not windows/arm64-specific. It is cleanup meant to make the port (and future ports) easier. Change-Id: I2d0072b377f73e49d7158ea304670c26f5486c59 Reviewed-on: https://go-review.googlesource.com/c/go/+/288794 Trust: Russ Cox <rsc@golang.org> Trust: Jason A. Donenfeld <Jason@zx2c4.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-02-19runtime: clean up system calls during cgo callback initRuss Cox
During a cgocallback, the runtime calls needm to get an m. The calls made during needm cannot themselves assume that there is an m or a g (which is attached to the m). In the old days of making direct system calls, the only thing you had to do for such functions was mark them //go:nosplit, to avoid the use of g in the stack split prologue. But now, on operating systems that make system calls through shared libraries and use code that saves state in the g or m before doing so, it's not safe to assume g exists. In fact, it is not even safe to call getg(), because it might fault deferencing the TLS storage to find the g pointer (that storage may not be initialized yet, at least on Windows, and perhaps on other systems in the future). The specific routines that are problematic are usleep and osyield, which are called during lock contention in lockextra, called from needm. All this is rather subtle and hidden, so in addition to fixing the problem on Windows, this CL makes the fact of not running on a g much clearer by introducing variants usleep_no_g and osyield_no_g whose names should make clear that there is no g. And then we can remove the various sketchy getg() == nil checks in the existing routines. As part of this cleanup, this CL also deletes onosstack on Windows. onosstack is from back when the runtime was implemented in C. It predates systemstack but does essentially the same thing. Instead of having two different copies of this code, we can use systemstack consistently. This way we need not port onosstack to each architecture. This CL is part of a stack adding windows/arm64 support (#36439), intended to land in the Go 1.17 cycle. This CL is, however, not windows/arm64-specific. It is cleanup meant to make the port (and future ports) easier. Change-Id: I3352de1fd0a3c26267c6e209063e6e86abd26187 Reviewed-on: https://go-review.googlesource.com/c/go/+/288793 Trust: Russ Cox <rsc@golang.org> Trust: Jason A. Donenfeld <Jason@zx2c4.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-11-24runtime: allow for usleep2HighRes to run without TLS setupAlex Brainman
This change adjusts usleep2HighRes so it does not crash when TLS is not configured. When g is not available, usleep2HighRes just calls usleep2 instead. Updates #8687 Change-Id: Idbb80f7b71d1da350a6a7df7c49154eb1ffe29a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/271907 Run-TryBot: Alex Brainman <alex.brainman@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com> Reviewed-by: Simon Rozman <simon@rozman.si> Trust: Jason A. Donenfeld <Jason@zx2c4.com> Trust: Alex Brainman <alex.brainman@gmail.com>
2020-10-26runtime,cmd/cgo: simplify C -> Go call pathAustin Clements
This redesigns the way calls work from C to exported Go functions. It removes several steps from the call path, makes cmd/cgo no longer sensitive to the Go calling convention, and eliminates the use of reflectcall from cgo. In order to avoid generating a large amount of FFI glue between the C and Go ABIs, the cgo tool has long depended on generating a C function that marshals the arguments into a struct, and then the actual ABI switch happens in functions with fixed signatures that simply take a pointer to this struct. In a way, this CL simply pushes this idea further. Currently, the cgo tool generates this argument struct in the exact layout of the Go stack frame and depends on reflectcall to unpack it into the appropriate Go call (even though it's actually reflectcall'ing a function generated by cgo). In this CL, we decouple this struct from the Go stack layout. Instead, cgo generates a Go function that takes the struct, unpacks it, and calls the exported function. Since this generated function has a generic signature (like the rest of the call path), we don't need reflectcall and can instead depend on the Go compiler itself to implement the call to the exported Go function. One complication is that syscall.NewCallback on Windows, which converts a Go function into a C function pointer, depends on cgocallback's current dynamic calling approach since the signatures of the callbacks aren't known statically. For this specific case, we continue to depend on reflectcall. Really, the current approach makes some overly simplistic assumptions about translating the C ABI to the Go ABI. Now we're at least in a much better position to do a proper ABI translation. For comparison, the current cgo call path looks like: GoF (generated C function) -> crosscall2 (in cgo/asm_*.s) -> _cgoexp_GoF (generated Go function) -> cgocallback (in asm_*.s) -> cgocallback_gofunc (in asm_*.s) -> cgocallbackg (in cgocall.go) -> cgocallbackg1 (in cgocall.go) -> reflectcall (in asm_*.s) -> _cgoexpwrap_GoF (generated Go function) -> p.GoF Now the call path looks like: GoF (generated C function) -> crosscall2 (in cgo/asm_*.s) -> cgocallback (in asm_*.s) -> cgocallbackg (in cgocall.go) -> cgocallbackg1 (in cgocall.go) -> _cgoexp_GoF (generated Go function) -> p.GoF Notably: 1. We combine _cgoexp_GoF and _cgoexpwrap_GoF and move the combined operation to the end of the sequence. This combined function also handles reflectcall's previous role. 2. We combined cgocallback and cgocallback_gofunc since the only purpose of having both was to convert a raw PC into a Go function value. We instead construct the Go function value in cgocallbackg1. 3. cgocallbackg1 no longer reaches backwards through the stack to get the arguments to cgocallback_gofunc. Instead, we just pass the arguments down. 4. Currently, we need an explicit msanwrite to mark the results struct as written because reflectcall doesn't do this. Now, the results are written by regular Go assignments, so the Go compiler generates the necessary MSAN annotations. This also means we no longer need to track the size of the arguments frame. Updates #40724, since now we don't need to teach cgo about the register ABI or change how it uses reflectcall. Change-Id: I7840489a2597962aeb670e0c1798a16a7359c94f Reviewed-on: https://go-review.googlesource.com/c/go/+/258938 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-18runtime: use CreateWaitableTimerEx to implement usleepAlex Brainman
@jstarks suggested that recent versions of Windows provide access to high resolution timers. See https://github.com/golang/go/issues/8687#issuecomment-656259353 for details. I tried to run this C program on my Windows 10 computer ``` #include <stdio.h> #include <Windows.h> #pragma comment(lib, "Winmm.lib") // Apparently this is already defined when I use msvc cl. //#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002; int usleep(HANDLE timer, LONGLONG d) { LARGE_INTEGER liDueTime; DWORD ret; LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds; LARGE_INTEGER Frequency; QueryPerformanceFrequency(&Frequency); QueryPerformanceCounter(&StartingTime); liDueTime.QuadPart = d; liDueTime.QuadPart = liDueTime.QuadPart * 10; // us into 100 of ns units liDueTime.QuadPart = -liDueTime.QuadPart; // negative for relative dure time if (!SetWaitableTimer(timer, &liDueTime, 0, NULL, NULL, 0)) { printf("SetWaitableTimer failed: errno=%d\n", GetLastError()); return 1; } ret = WaitForSingleObject(timer, INFINITE); if (ret != WAIT_OBJECT_0) { printf("WaitForSingleObject failed: ret=%d errno=%d\n", ret, GetLastError()); return 1; } QueryPerformanceCounter(&EndingTime); ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; ElapsedMicroseconds.QuadPart *= 1000000; ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; printf("delay is %lld us - slept for %lld us\n", d, ElapsedMicroseconds.QuadPart); return 0; } int testTimer(DWORD createFlag) { HANDLE timer; timer = CreateWaitableTimerEx(NULL, NULL, createFlag, TIMER_ALL_ACCESS); if (timer == NULL) { printf("CreateWaitableTimerEx failed: errno=%d\n", GetLastError()); return 1; } usleep(timer, 1000LL); usleep(timer, 100LL); usleep(timer, 10LL); usleep(timer, 1LL); CloseHandle(timer); return 0; } int main() { printf("\n1. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is off\n"); testTimer(0); printf("\n2. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is off\n"); testTimer(CREATE_WAITABLE_TIMER_HIGH_RESOLUTION); timeBeginPeriod(1); printf("\n3. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is on\n"); testTimer(0); printf("\n4. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is on\n"); testTimer(CREATE_WAITABLE_TIMER_HIGH_RESOLUTION); } ``` and I see this output ``` 1. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is off delay is 1000 us - slept for 4045 us delay is 100 us - slept for 3915 us delay is 10 us - slept for 3291 us delay is 1 us - slept for 2234 us 2. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is off delay is 1000 us - slept for 1076 us delay is 100 us - slept for 569 us delay is 10 us - slept for 585 us delay is 1 us - slept for 17 us 3. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is on delay is 1000 us - slept for 742 us delay is 100 us - slept for 893 us delay is 10 us - slept for 414 us delay is 1 us - slept for 920 us 4. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is on delay is 1000 us - slept for 1466 us delay is 100 us - slept for 559 us delay is 10 us - slept for 535 us delay is 1 us - slept for 5 us ``` That shows, that indeed using CREATE_WAITABLE_TIMER_HIGH_RESOLUTION will provide sleeps as low as about 500 microseconds, while our current approach provides about 1 millisecond sleep. New approach also does not require for timeBeginPeriod to be on, so this change solves long standing problem with go programs draining laptop battery, because it calls timeBeginPeriod. This change will only run on systems where CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available. If not available, the runtime will fallback to original code that uses timeBeginPeriod. This is how this change affects benchmark reported in issue #14790 name               old time/op  new time/op  delta ChanToSyscallPing  1.05ms ± 2%  0.68ms ±11%  -35.43%  (p=0.000 n=10+10) The benchmark was run with GOMAXPROCS set to 1. Fixes #8687 Updates #14790 Change-Id: I5b97ba58289c088c17c05292e12e45285c467eae Reviewed-on: https://go-review.googlesource.com/c/go/+/248699 Run-TryBot: Alex Brainman <alex.brainman@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Austin Clements <austin@google.com>
2020-02-25runtime: allow float syscall return values on windows amd64Richard Wilkes
RELNOTE=yes Fixes #37273 Change-Id: Iedb7eab185dfeccb1b26902ef36411d2c53ea3e0 GitHub-Last-Rev: bbe30ba45d4a1bd53757b5824ad28024d5e2b179 GitHub-Pull-Request: golang/go#37380 Reviewed-on: https://go-review.googlesource.com/c/go/+/220578 Run-TryBot: Alex Brainman <alex.brainman@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Alex Brainman <alex.brainman@gmail.com>