0

I'm writing my own F#-esque language and I'm using LLVM for code generation. I want my language to support continuation passing style and I think I've got TCO figured out but I cannot figure out how to make continuations use heap memory instead of stack memory. As far as I can tell there is no direct mechanism for making a function's alloca call a custom allocation function. Do I have to implement a custom backend for this?

Gabriel
  • 11

1 Answers1

0

LLVM does not have a built in mechanism for such an abstraction, because it does not really implement a language level stack. It implements an activation record allocation stack. In C, these map 1:1, but once you explore more complex abstractions, these do not necessarily map 1:1.

Unless you are only talking about initial captures, you are likely to run into the issue that LLVM has no way to resume a function.

Typically, you would implement closures by using multiple activation records by splitting up your closure up into a state machine. One for the initial capture and then one for each entry point that you could need to resume to. The LLVM stack can be used to store values that are local to a specific state, but when values need to be stored between states, you will need to create some sort of struct datastructure, to store them in, and then store that struct in an appropriate place, for your languages concept of what a closure value is.

Depending on the implementation, you may choose to have a single struct which you mutate, or treat it as an immutable datastructure, where each state is a function from the initial values to values at the pause point.

It may also be useful to record what state you are in in this datastructure, in order to facilitate dispatch.

To take the concrete example of F#, an F# closure is just a class, containing a field for each captured value, and a virtual Invoke method. All captured values are rewritten to field accesses against the this parameter in the Invoke method, whilst the creation of the closure is rewritten to assign the values of the variables at the point of capture to the newly allocated closure object's fields.