I read that coroutine_handle
can be reconstructed from a reference to the coroutine's promise object using coroutine_handle<Promise>::from_promise()
function. To my knowledge, the promise object is defined like this:
class resumable{
public:
struct promise_type;
bool resume();
};
struct resumable::promise_type{
resumable get_return_object() {/**/}
auto initial_suspend() {/**/}
auto final_suspend() {/**/}
void return_void() {}
void unhandled_exception();
};
I am failing to figure out how reconstruction could work given the fact that promise_type
doesn't hold any reference to the coroutine handle. Just the opposite, the coroutine handle stores the reference to the promise object, which can be returned by the promise()
method of the handle. I can't find any information on what actually happens in from_promise
function.
It works by fiat. That is, it works because the standard says that it works, and implementations must therefore find a way to implement coroutines in such a way that it is possible.
When creating a coroutine, the implementation creates two things: the coroutine_handle
(or rather, the guts of it to which the coroutine_handle
points) and the promise object. The location of both of these things is controlled entirely by the compiler. So, the compiler could very easily allocate them contiguously with each other, such that a coroutine's stack would essentially start with a struct {coroutine_guts handle; Promise promise};
, where coroutine_guts
is the object that the coroutine_handle
points to.
Given that knowledge, you know that the handle for any promise type lives sizeof(coroutine_guts)
bytes before any promise
object's address (alignment requirements of the Promise
type can adjust this, but such things can be queried from the type). And since from_promise
takes a promise object, you can just offset the pointer to get the coroutine_guts
and shove that in a coroutine_handle<Promise>
.
Now, that is just one way of doing it; an implementation doesn't have to do it this way. What matters is that the implementation has control over where the promise object lives relative to the coroutine internal data. Or more specifically, the promise lives inside of that internal data. Regardless of how you look at it, the compiler knows everything it needs to in order to convert the address of a promise into the internal data needed to fill in a coroutine_handle
.