stash0-wasm-stack-128kb.patch raw
1 diff --git a/src/internal/cpu/cpu_x86.mx b/src/internal/cpu/cpu_x86.mx
2 index b418c188..403e963e 100644
3 --- a/src/internal/cpu/cpu_x86.mx
4 +++ b/src/internal/cpu/cpu_x86.mx
5 @@ -8,14 +8,10 @@ package cpu
6
7 const CacheLinePadSize = 64
8
9 -// cpuid is implemented in cpu_x86.s.
10 -func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
11 -
12 -// xgetbv with ecx = 0 is implemented in cpu_x86.s.
13 -func xgetbv() (eax, edx uint32)
14 -
15 -// getGOAMD64level is implemented in cpu_x86.s. Returns number in [1,4].
16 -func getGOAMD64level() int32
17 +// Moxie stubs: assembly intrinsics not available, report no features.
18 +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { return 0, 0, 0, 0 }
19 +func xgetbv() (eax, edx uint32) { return 0, 0 }
20 +func getGOAMD64level() int32 { return 1 }
21
22 const (
23 // ecx bits
24 diff --git a/src/internal/runtime/syscall/syscall_linux.mx b/src/internal/runtime/syscall/syscall_linux.mx
25 index 49e5f8de..ca76333c 100644
26 --- a/src/internal/runtime/syscall/syscall_linux.mx
27 +++ b/src/internal/runtime/syscall/syscall_linux.mx
28 @@ -14,7 +14,17 @@ import (
29 // only contains very minimal support for Linux.
30
31 // Syscall6 calls system call number 'num' with arguments a1-6.
32 -func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr)
33 +// Moxie: implemented via libc syscall(2) instead of raw assembly.
34 +func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr) {
35 + r := libc_syscall(int32(num), a1, a2, a3, a4, a5, a6)
36 + if r < 0 {
37 + return 0, 0, uintptr(-r)
38 + }
39 + return uintptr(r), 0, 0
40 +}
41 +
42 +//export syscall
43 +func libc_syscall(num int32, a1, a2, a3, a4, a5, a6 uintptr) int64
44
45 func EpollCreate1(flags int32) (fd int32, errno uintptr) {
46 r1, _, e := Syscall6(SYS_EPOLL_CREATE1, uintptr(flags), 0, 0, 0, 0, 0)
47 diff --git a/src/runtime/gc_stack_portable.mx b/src/runtime/gc_stack_portable.mx
48 index ccd2a5e7..66c14607 100644
49 --- a/src/runtime/gc_stack_portable.mx
50 +++ b/src/runtime/gc_stack_portable.mx
51 @@ -3,18 +3,17 @@
52 package runtime
53
54 import (
55 + "internal/task"
56 "runtime/volatile"
57 "unsafe"
58 )
59
60 -// stackChainStart anchors the compiler-generated stack chain that tracks
61 -// heap pointers in WASM function locals. MakeGCStackSlots inserts stores
62 -// to this global at every function entry/exit. The volatile load in
63 -// markStack prevents LLVM from DCE'ing those stores.
64 -//
65 -// Declared as a regular var (not //go:extern) so the linker places it at
66 -// a non-zero BSS address. With //go:extern, wasm-ld resolves it to
67 -// address 0, which triggers a nil panic on the volatile load.
68 +func gcMarkReachable() {
69 + markStack()
70 + findGlobals(markRoots)
71 +}
72 +
73 +//go:extern runtime.stackChainStart
74 var stackChainStart *stackChainObject
75
76 type stackChainObject struct {
77 @@ -22,16 +21,37 @@ type stackChainObject struct {
78 numSlots uintptr
79 }
80
81 -func gcMarkReachable() {
82 - markStack()
83 - findGlobals(markRoots)
84 -}
85 -
86 +// markStack marks all root pointers found on the stack.
87 +//
88 +// - Goroutine stacks are heap allocated and always reachable in some way
89 +// (for example through internal/task.currentTask) so they will always be
90 +// scanned.
91 +// - The system stack (aka startup stack) is not heap allocated, so even
92 +// though it may be referenced it will not be scanned by default.
93 +//
94 +// The compiler also inserts code to store all globals in a chain via
95 +// stackChainStart. Luckily we don't need to scan these, as these globals are
96 +// stored on the goroutine stack and are therefore already getting scanned.
97 func markStack() {
98 - // Force LLVM to keep stackChainStart (and the MakeGCStackSlots
99 - // bookkeeping that writes to it) alive.
100 + // Hack to force LLVM to consider stackChainStart to be live.
101 + // Without this hack, loads and stores may be considered dead and objects on
102 + // the stack might not be correctly tracked. With this volatile load, LLVM
103 + // is forced to consider stackChainStart (and everything it points to) as
104 + // live.
105 volatile.LoadUint32((*uint32)(unsafe.Pointer(&stackChainStart)))
106 - markRoots(getCurrentStackPointer(), stackTop)
107 +
108 + // Scan the system stack.
109 + var sysSP uintptr
110 + if task.OnSystemStack() {
111 + // We are on the system stack.
112 + // Use the current stack pointer.
113 + sysSP = getCurrentStackPointer()
114 + } else {
115 + // We are in a goroutine.
116 + // Use the saved stack pointer.
117 + sysSP = savedStackPointer
118 + }
119 + markRoots(sysSP, stackTop)
120 }
121
122 // trackPointer is a stub function call inserted by the compiler during IR
123 @@ -39,13 +59,12 @@ func markStack() {
124 // code.
125 func trackPointer(ptr, alloca unsafe.Pointer)
126
127 -// swapStackChain is referenced by internal/task for goroutine switching.
128 -// No-op in moxie (no goroutines).
129 -func swapStackChain(dst **stackChainObject) {}
130 -
131 -// scanstack is called from internal/task via go:linkname.
132 -func scanstack(sp uintptr) {
133 - markRoots(sp, stackTop)
134 +// swapStackChain swaps the stack chain.
135 +// This is called from internal/task when switching goroutines.
136 +func swapStackChain(dst **stackChainObject) {
137 + *dst, stackChainStart = stackChainStart, *dst
138 }
139
140 -func gcResumeWorld() {}
141 +func gcResumeWorld() {
142 + // Nothing to do here (single threaded).
143 +}
144 diff --git a/src/runtime/panic.mx b/src/runtime/panic.mx
145 index 0a616088..e4ec5ada 100644
146 --- a/src/runtime/panic.mx
147 +++ b/src/runtime/panic.mx
148 @@ -10,16 +10,14 @@ import (
149 // trap is a compiler hint that this function cannot be executed. It is
150 // translated into either a trap instruction or a call to abort().
151 //
152 -//go:nobounds
153 -func trap() {
154 - trap_arch()
155 -}
156 +//export llvm.trap
157 +func trap()
158
159 // Inline assembly stub. It is essentially C longjmp but modified a bit for the
160 // purposes of Moxie. It restores the stack pointer and jumps to the given pc.
161 -func moxie_longjmp(frame *deferFrame) {
162 - moxie_longjmp_arch(frame)
163 -}
164 +//
165 +//export moxie_longjmp
166 +func moxie_longjmp(frame *deferFrame)
167
168 // Compiler intrinsic.
169 // Returns whether recover is supported on the current architecture.
170 diff --git a/src/runtime/pipe_channel.mx b/src/runtime/pipe_channel.mx
171 index bd026e62..be8115e5 100644
172 --- a/src/runtime/pipe_channel.mx
173 +++ b/src/runtime/pipe_channel.mx
174 @@ -319,8 +319,8 @@ func PipeChanSend(ch *channel, encoded []byte) bool {
175 return false
176 }
177 ticks++
178 - if ticks == 60000 {
179 - println("pipe: send stalled 60s fd=", ch.pipeBoundFd, "chan=", ch.pipeChanID)
180 + if ticks == 3000 {
181 + println("pipe: send stalled 3s fd=", ch.pipeBoundFd, "chan=", ch.pipeChanID)
182 }
183 sleepTicks(nanosecondsToTicks(1_000_000))
184 }
185 @@ -355,8 +355,8 @@ func PipeChanRecv(ch *channel) ([]byte, bool) {
186 }
187 if n < 0 {
188 ticks++
189 - if ticks == 60000 {
190 - println("pipe: recv stalled 60s fd=", ch.pipeBoundFd, "chan=", ch.pipeChanID)
191 + if ticks == 3000 {
192 + println("pipe: recv stalled 3s fd=", ch.pipeBoundFd, "chan=", ch.pipeChanID)
193 }
194 sleepTicks(nanosecondsToTicks(1_000_000))
195 continue
196 diff --git a/src/runtime/poll.mx b/src/runtime/poll.mx
197 index fad0a083..f117727c 100644
198 --- a/src/runtime/poll.mx
199 +++ b/src/runtime/poll.mx
200 @@ -1,5 +1,3 @@
201 -//go:build !moxie.wasm
202 -
203 package runtime
204
205 // Netpoller for moxie on Linux using epoll.
206 diff --git a/src/runtime/runtime.mx b/src/runtime/runtime.mx
207 index d66ab00c..d9800831 100644
208 --- a/src/runtime/runtime.mx
209 +++ b/src/runtime/runtime.mx
210 @@ -57,6 +57,12 @@ func memzero(ptr unsafe.Pointer, size uintptr)
211 // the current stack pointer in a platform-independent way.
212 func stacksave() unsafe.Pointer
213
214 +// Special LLVM intrinsic that returns the SP register on entry to the calling
215 +// function.
216 +//
217 +//export llvm.sponentry.p0
218 +func llvm_sponentry() unsafe.Pointer
219 +
220 //export strlen
221 func strlen(ptr unsafe.Pointer) uintptr
222
223 diff --git a/src/runtime/runtime_wasm.mx b/src/runtime/runtime_wasm.mx
224 index 8e024c86..0e894082 100644
225 --- a/src/runtime/runtime_wasm.mx
226 +++ b/src/runtime/runtime_wasm.mx
227 @@ -67,7 +67,7 @@ func growHeap() bool {
228 if oldPages == -1 {
229 return false
230 }
231 - setHeapEnd(uintptr(oldPages+8) * wasmPageSize)
232 + heapEnd = uintptr(oldPages+8) * wasmPageSize
233 return true
234 }
235
236 @@ -76,7 +76,7 @@ func growHeap() bool {
237 //go:extern __data_start
238 var globalsStart [0]byte
239
240 -//go:extern __heap_base
241 +//go:extern __data_end
242 var globalsEnd [0]byte
243
244 // Timing functions for WASM.
245 @@ -153,11 +153,9 @@ func wasmAlloc(size int32) int32 {
246 //
247 //export _start
248 func _start() {
249 - stackTop = getCurrentStackPointer()
250 allocateHeap()
251 initRand()
252 initHeap()
253 - wasmTickOffset = monotime()
254 initAll()
255 wasmExportsReady = true
256 callMain()
257 diff --git a/src/syscall/syscall_linux.mx b/src/syscall/syscall_linux.mx
258 index d733ca9b..c15dfafd 100644
259 --- a/src/syscall/syscall_linux.mx
260 +++ b/src/syscall/syscall_linux.mx
261 @@ -27,10 +27,10 @@ import (
262 // inbetween.
263
264 //go:linkname runtime_entersyscall runtime.entersyscall
265 -func runtime_entersyscall()
266 +func runtime_entersyscall() {}
267
268 //go:linkname runtime_exitsyscall runtime.exitsyscall
269 -func runtime_exitsyscall()
270 +func runtime_exitsyscall() {}
271
272 // N.B. For the Syscall functions below:
273 //
274 @@ -99,8 +99,14 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
275 return
276 }
277
278 -func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr)
279 -func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1 uintptr, err Errno)
280 +func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
281 + r1, r2, _ = RawSyscall6(trap, a1, a2, a3, 0, 0, 0)
282 + return
283 +}
284 +func rawVforkSyscall(trap, a1, a2, a3 uintptr) (r1 uintptr, err Errno) {
285 + r1, _, err = RawSyscall6(trap, a1, a2, a3, 0, 0, 0)
286 + return
287 +}
288
289 /*
290 * Wrapped
291 @@ -1101,7 +1107,11 @@ func Getpgrp() (pid int) {
292 // all threads are in sync.
293 //
294 //go:uintptrescapes
295 -func runtime_doAllThreadsSyscall(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
296 +func runtime_doAllThreadsSyscall(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
297 + // Moxie: single-threaded, just do the syscall directly.
298 + r1, r2, err = RawSyscall6(trap, a1, a2, a3, a4, a5, a6)
299 + return
300 +}
301
302 // AllThreadsSyscall performs a syscall on each OS thread of the Go
303 // runtime. It first invokes the syscall on one thread. Should that
304