0%

coro-asm 1.句柄结构

这一节分析协程状态结构,指的是 官方文档中的 coroutine state

the coroutine state, which is internal, dynamically-allocated storage (unless the allocation is optimized out), object that contains

  • the promise object
  • the parameters (all copied by value)
  • some representation of the current suspension point, so that a resume knows where to continue, and a destroy knows what local variables were in scope
  • local variables and temporaries whose lifetime spans the current suspension point.

姑且命名此结构为CoroState

先将分析结果贴出来,此结构布局只针对样例。
另一方面,因为coroutine与coroutine函数各自独立,所以可以猜测CoroState中与临时或本地变量有关的东西应该是指针或者状态式的。

CoroState 结构布局

type range naming meaning
void * 0-8 entry_ resume entry
void * 8-16 entry2_ not seen yet
void * 16-24 promise_ promise itself(no pointer)
void * 24-32 act_coro_ actived coro in its frame ?
int16_t 32-34 stat_ coro state see [coro state](#coro 状态)
bool 34-35 ifvalid_ flag indicates if coro frame is valid

coro 状态

这里有一个很重要的状态成员 stat_,先将状态含义贴出来,以便于阅读后边的代码

val mean
0 after call promise::get_return_object
2 after call promise::initial_suspend

汇编分析

结论(cc)

  1. CoroFunc 本身被gcc编译成空壳函数体,其内部的语句都编译在CoroFunc.Frame,即另一个代码区。其本身只负责初始化Coro帧并调用promise::initial_suspendpromise::get_return_objectcoroutine::resume. 伪码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    FORCE_NOINLINE coroutine CAwait1(){
    CoroState * frame = new CoroState;
    frame->ifValid_ =true;
    frame->entry_ = 0xaaa;// resume entry
    frame->entry2_ = 0xbbb;// another resume point
    auto pro =frame->promise_;
    pro->promise();// 初始化promise
    coroutine ret = pro->get_return_object(); // 拿到返回对象
    co_await pro->initial_suspend();
    }

compile config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cmake_minimum_required(VERSION 3.10)

set(${CMAKE_HOST_SYSTEM_NAME} TRUE)
set(CMAKE_CXX_STANDARD 20)


project(TEST)
aux_source_directory(. SRCS)

if(Linux)
add_compile_options(-fcoroutines)
message(CMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG})
set(CMAKE_CXX_FLAGS_DEBUG "-O1 -g -fno-exceptions")
# add_link_options("-T" "${CMAKE_CURRENT_LIST_DIR}/ls.ld")
endif()

include_directories(.)

foreach(src ${SRCS})
string(REGEX REPLACE ".*/([^/\\]*)\.cpp" "\\1" name "${src}")
message("src=${src} name=${name}")
add_executable(${name} ${src})
endforeach()

utils.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <coroutine>
// #include <utils.hpp>

#pragma GCC push_options
#pragma GCC optimize("O0")
extern "C" FORCE_NOINLINE void TagFunc(int)
{
}
struct suspend_always_rt
{
constexpr bool await_ready() const noexcept
{
return false;
}

constexpr void await_suspend(std::coroutine_handle<>) const noexcept {}

constexpr void await_resume() const noexcept {}
};
#pragma GCC pop_options

struct promise;
struct coroutine : std::coroutine_handle<promise>
{
using promise_type = ::promise;
};


extern "C" struct promise
{
FORCE_NOINLINE promise()
{
TagFunc(1);
}
FORCE_NOINLINE promise(int i_)
: i(i_)
{
TagFunc(2);
}
FORCE_NOINLINE coroutine get_return_object()
{
TagFunc(3);
return {coroutine::from_promise(*this)};
}
FORCE_NOINLINE suspend_always_rt initial_suspend() noexcept
// FORCE_NOINLINE std::suspend_always initial_suspend() noexcept
{
TagFunc(4);
return {};
}
FORCE_NOINLINE std::suspend_always final_suspend() noexcept
{
TagFunc(5);
return {};
}
FORCE_NOINLINE void return_void()
{
TagFunc(6);
}
FORCE_NOINLINE void unhandled_exception()
{
}
int i = 0;
};

FORCE_NOINLINE coroutine CAwait1()
{
TagFunc(7);
co_return;
}

int main()
{
auto c1 = CAwait1();
c1.resume();

}

Appendix

  • _Znwm and _ZdlPv 是 new 和delete的符号名

  • bt 指令: bit get

  • test 指令: 按位与操作,会设置 CF(carry flag)