I planned to implement a Go-like runtime (v1) in Zig - with Stack Stitching w/ Hot Split.
I got this working for the happy path, but I want to be able to use Zig’s defer stack to have fiber-fault isolation.
I transpile a language to Zig, so I can make sure that any locks, heap allocations, resources etc are put on the defer / errdefer stack, and this makes cleaning up a fiber overflow easy in theory.
But is there any way to get this working with Stack Stitching w/ Hot Split?
Essentially, I have an LLVM Machine Pass that injects asm at the very top of every function (transpiled) like so:
entry:
# START MY CUSTOM PROLOGUE BEFORE ANYTHING ELSE
jmp resume if (rsp - frame_size > LIMIT)
call morestack # This creates a larger stack, switches to it, hijacks the return to CALL lessstack, which moves the stack pointer back to the old stack, then RETS whatever would normally be returned
# morestack JUMPs to here (not RET)
resume:
# END MY PROLOGUE
# the existing function …
This just works if the fiber doesn’t error. But a fiber not erroring for any reason is completely un-realistic. I’m lost at how I can prove this will just work with the defer and errdefer stack, unwinding, backtracing, etc.
For one, I’m in way over my head. I can’t find out definitely what I must guarantee to ensure Zig’s unwinding would just work. Under the hood, I thought errors are just returned not unwound, so this shouldn’t really be a problem. If it works with normal returns, it should just work with errors. But I can’t make assumptions. I’m not sure how much testing would be involved for me to feel confident it actually works, instead of just coincidentally passes whatever tests I write. Lastly, Zig is in flux, so I’m hoping there could be a solution that will be future proof.
Naively, I assumed this would work. Now I’m feeling the pain of my stupidity /=
Stack Splitting would effectively be useless if it only works with fibers that don’t ever error.