1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
; Nicholas Noll 2019
;
; ===================================================================
%use altreg
bits 64
default rel
global _newcoro
global _coroyield
; ===================================================================
section .text
; -------------------------------------------------------------------
%assign L.coro -8
%assign L.func -16
coroinit:
mov R7, [RBP + L.coro]
mov R6, R0
call [RBP + L.func]
rerun:
mov R7, [RBP + L.coro]
mov R6, R0
call _coroyield
jmp rerun
; -------------------------------------------------------------------
; # Register Mapping
;
; R0 R1 R2 R3 R4 R5 R6 R7 R8 ...
; RAX RCX RDX RBX RSP RBP RSI RDI R8 ...
;
; # Sys V calling convention
; func(R7, R6, R2, R1, R8, R9, Z0-7): R0
;
; # Stack layout of an in-flight coro
; *coro
; *func
; *bp (base pointer of stack)
; ....... STACK .........
; Saved Clobbers
;
; ###
; Stack layout of an init coro
; Stores the func pointer to init
; Stores the clobber registers.
;
; L.coro [8]
; L.func [7]
; coroinit [6]
; RBP [5]
; R3 [4]
; R12 [3]
; R13 [2]
; R14 [1]
; R15 [0]
%define WORDSZ 8
%define NSAVES 9
; coro *coro·new(co *coro, fn func, bp *stack)
_newcoro:
lea R0, [coroinit] ; Store address of init function
lea R1, [R2 - NSAVES*WORDSZ] ; Store offset address of stack
mov [R1 + 8*WORDSZ], R7 ; Store context pointer
mov [R1 + 7*WORDSZ], R6 ; Store function pointer
mov [R1 + 6*WORDSZ], R0 ; Store initializer pointer
mov [R1 + 5*WORDSZ], R2 ; Store stack base pointer
xor R0, R0
; Start of mutable stack
; Blank out the clobbers
mov [R1 + 4*WORDSZ], R0 ; R3
mov [R1 + 3*WORDSZ], R0 ; R12
mov [R1 + 2*WORDSZ], R0 ; R13
mov [R1 + 1*WORDSZ], R0 ; R14
mov [R1 + 0*WORDSZ], R0 ; R15
mov [R7], R1
ret
; Saves register state
%macro pushclobs 0
push RBP
push R3
push R12
push R13
push R14
push R15
%endmacro
; Restores register state
%macro popclobs 0
pop R15
pop R14
pop R13
pop R12
pop R3
pop RBP
%endmacro
; uintptr coro.yield(co *coro, data uintptr)
_coroyield:
pushclobs
mov R0, R6 ; Move return value into return register.
xchg RSP, [R7] ; Atomically swap the stack pointer with the yieldee.
popclobs
ret
|