luncliff/coroutine

msvc/clang intrinsic

luncliff opened this issue · 0 comments

Build Status Build status

Research about compiler intrinsics and its operation results

Reference

Frame Layout

Mostly memory alignment is multiply of 16.

// from VC++ <experimental/resumable>
template<typename T>
constexpr auto aligned_size_v = ((sizeof(T) + 16 - 1) & ~(16 - 1));

// in short this is `goto` 
using procedure_t = void(__cdecl*)(void*);

Each compiler's memory layout of coroutine frame will be described below.

MSVC

 | Promise | Frame Prefix | Local variables | 
            \
            resumable_handle<void>
address: low-->high

The structure of frame prefix is like this

// - Note
//      MSVC coroutine frame's prefix. See `_Resumable_frame_prefix`
struct msvc_frame_prefix final
{
    procedure_t factivate;
    uint16_t index;
    uint16_t flag;
};
static_assert(sizeof(msvc_frame_prefix) == 16);

Clang

 | Frame Prefix | Promise | ? | Local variables | 
  \
  resumable_handle<void>
address: low-->high

? seems like a guard. When it's corrupted, builtin intrinsics makes a crash.

The structure of frame prefix is like this

// - Note
//      Clang coroutine frame's prefix. See reference docs above
struct clang_frame_prefix final
{
    procedure_t factivate;
    procedure_t fdestroy;
};
static_assert(sizeof(clang_frame_prefix) == 16);

Compiler Intrinsic

intrinsics and their behavior

MSVC

// <experimental/resumable>

extern "C" size_t _coro_resume(void*);
extern "C" void _coro_destroy(void*);
extern "C" size_t _coro_done(void*);

Clang

// <experimental/coroutine>

void __builtin_coro_resume(void *addr);
void __builtin_coro_destroy(void *addr);
bool __builtin_coro_done(void *addr);

Porting Issue