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