all: add support for windows/amd64

This uses Mingw-w64, which seems to be the de facto standard for porting
Unixy programs to Windows.
This commit is contained in:
Ayke van Laethem
2021-11-05 13:23:08 +01:00
committed by Ron Evans
parent 41bcad9c19
commit 869e917dc6
26 changed files with 841 additions and 161 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
// +build scheduler.tasks,amd64
// +build scheduler.tasks,amd64,!windows
package task
@@ -0,0 +1,57 @@
// Windows on amd64 has a slightly different ABI than other (*nix) systems.
// Therefore, assembly functions need to be tweaked slightly.
.section .text.tinygo_startTask,"ax"
.global tinygo_startTask
tinygo_startTask:
// Small assembly stub for starting a goroutine. This is already run on the
// new stack, with the callee-saved registers already loaded.
// Most importantly, r12 contain the pc of the to-be-started function and
// r13 contain the only argument it is given. Multiple arguments are packed
// into one by storing them in a new allocation.
// Set the first argument of the goroutine start wrapper, which contains all
// the arguments.
movq %r13, %rcx
// Branch to the "goroutine start" function.
callq *%r12
// After return, exit this goroutine. This is a tail call.
jmp tinygo_pause
.global tinygo_swapTask
.section .text.tinygo_swapTask,"ax"
tinygo_swapTask:
// This function gets the following parameters:
// %rcx = newStack uintptr
// %rdx = oldStack *uintptr
// Save all callee-saved registers:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rsi
pushq %rdi
pushq %rbp
pushq %rbx
// Save the current stack pointer in oldStack.
movq %rsp, (%rdx)
// Switch to the new stack pointer.
movq %rcx, %rsp
// Load saved register from the new stack.
popq %rbx
popq %rbp
popq %rdi
popq %rsi
popq %r12
popq %r13
popq %r14
popq %r15
// Return into the new task, as if tinygo_swapTask was a regular call.
ret
@@ -0,0 +1,66 @@
// +build scheduler.tasks,amd64,windows
package task
// This is almost the same as task_stack_amd64.go, but with the extra rdi and
// rsi registers saved: Windows has a slightly different calling convention.
import "unsafe"
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_amd64_windows.S that relies on
// the exact layout of this struct.
type calleeSavedRegs struct {
rbx uintptr
rbp uintptr
rdi uintptr
rsi uintptr
r12 uintptr
r13 uintptr
r14 uintptr
r15 uintptr
pc uintptr
}
// archInit runs architecture-specific setup for the goroutine startup.
func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
// Store the initial sp for the startTask function (implemented in assembly).
s.sp = uintptr(unsafe.Pointer(r))
// Initialize the registers.
// These will be popped off of the stack on the first resume of the goroutine.
// Start the function at tinygo_startTask (defined in
// src/internal/task/task_stack_amd64_windows.S). This assembly code calls a
// function (passed in r12) with a single argument (passed in r13). After
// the function returns, it calls Pause().
r.pc = uintptr(unsafe.Pointer(&startTask))
// Pass the function to call in r12.
// This function is a compiler-generated wrapper which loads arguments out
// of a struct pointer. See createGoroutineStartWrapper (defined in
// compiler/goroutine.go) for more information.
r.r12 = fn
// Pass the pointer to the arguments struct in r13.
r.r13 = uintptr(args)
}
func (s *state) resume() {
swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
}
// SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0.
func SystemStack() uintptr {
return systemStack
}