Skip to content

Proposal: ability to execute a function on a different stack #1207

Open
@andrewrk

Description

@andrewrk

Here is a snippet from the Semantics document:

Stack Overflow

Call stack space is limited by unspecified and dynamically varying constraints and is a source of nondeterminism. If program call stack usage exceeds the available call stack space at any time, the execution in the WebAssembly instance is terminated and abnormal termination is reported to the outside environment.

Implementations must have an internal maximum call stack size, and every call must take up some resources toward exhausting that size (of course, dynamic resources may be exhausted much earlier). This rule exists to avoid differences in observable behavior; if some implementations have this property and others don’t, the same program which runs successfully on some implementations may consume unbounded resources and fail on others. Also, in the future, it is expected that WebAssembly will add some form of stack-introspection functionality, in which case such optimizations would be directly observable.

Support for explicit tail calls is planned in the future 🦄, which would add an explicit tail-call operator with well-defined effects on stack introspection.

I am the creator of Zig, an LLVM-based programming language which supports WebAssembly as one of many architecture backends.

In Zig we take stack overflow very seriously. In fact, recursion is a compile error unless you use a builtin function @newStackCall in order to make the recursive call on an explicitly allocated stack. Combining this with determining stack upper bound size at compile-time, Zig eliminates the possibility of stack overflow.

For most architectures, this works with the following LLVM IR code:

  %6 = call i8* @llvm.stacksave(), !dbg !45
  call void @llvm.write_register.i64(metadata !47, i64 %5), !dbg !45
  call fastcc void @foo(), !dbg !45
  call void @llvm.stackrestore(i8* %6), !dbg !45
...
!47 = !{!"rsp\00"}

That is, it modifies the stack pointer register to point to the new stack memory, makes the function call, and then restores the stack pointer register.

This proposal is to support these semantics, in one of 2 ways:

  • Allow modification of the stack pointer so that the LLVM IR above can lower to WebAssembly.
  • Support a builtin function directly which performs a function call using an explicitly provided memory buffer as the stack.

Metadata

Metadata

Assignees

No one assigned

    Labels

    asyncstack switching, JSPI, async, green threads, coroutines

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions