• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 实现描述
2
3重要说明:目前 AbcKit 支持 JS、ArkTS 和静态 ArkTS,但**对静态 ArkTS 的支持处于试验阶段**。
4编译后的 JS 和 ArkTS 存储在"动态"方舟字节码格式的文件中,静态 ArkTS 存储在"静态"方舟字节码格式的文件中。
5AbcKit 根据字节码的格式使用"动态"或"静态"的方式去处理文件。
6
7请先查看 [cookbook](mini_cookbook.md) 以了解用户视角的API。
8
91. [两种类型的字节码文件](#两种类型的-abc-文件)
102. [C API 和 C++ API](#c-api-和-c-api)
113. [按组件的控制流](#按组件的控制流)
124. [按源文件的控制流](#按源文件的控制流)
135. [动态和静态文件格式的处理](#动态和静态文件格式之间的分发)
146. [数据结构(上下文)和不透明指针](#数据结构上下文和不透明指针)
157. [数据结构(上下文)实现](#数据结构上下文实现)
168. [头文件命名冲突](#头文件命名冲突)
179. [字节码<-->中间表示](#字节码--中间表示)
18
19## 两种类型的 abc 文件
20
21**AbcKit 支持两种类型的字节码文件**:动态和静态。
22根据字节码文件类型可使用以下两种类型的组件:
23
241. `panda::panda_file` 和 `ark::panda_file`
252. `panda::abc2program` 和 `ark::abc2program`
263. `panda::pandasm` 和 `ark::pandasm`
274. IR 构建器:`libabckit::IrBuilderDynamic` 和 `ark::compiler::IrBuilder`
285. 代码生成:`libabckit::CodeGenDynamic` 和 `libabckit::CodeGenStatic`
29
30注意:`panda::` 是动态运行时命名空间,`ark::` 是静态运行时命名空间。
31
32只有一个静态运行时编译器用于 AbcKit 图表示:`ark::compiler::Graph`。
33
34## C API 和 C++ API
35
36AbcKit 提供两种 API:C API 和 C++ API。
37
38### C API
39
40所有 C API 都存储在 `./include/c` 文件夹中,目录结构如下:
41
42```
43include/c/
44├── abckit.h                  // 入口点 API
45├── api_version.h             // API 版本定义
46├── declarations.h            // 基础声明
47├── metadata_core.h           // 用于语言无关元数据检查/转换的 API
48├── extensions
49│   ├── arkts
50│   │   └── metadata_arkts.h  // 用于语言特定(ArkTS 和静态 ArkTS)元数据检查/转换的 API
51│   └── js
52│       └── metadata_js.h     // 用于语言特定(JS)元数据检查/转换的 API
53├── ir_core.h                 // 用于语言无关图检查/转换的 API
54├── isa
55│   ├── isa_dynamic.h         // 用于语言特定(JS 和 ArkTS)图检查/转换的 API
56│   └── isa_static.h          // 用于语言特定(静态 ArkTS)图检查/转换的 API(此头文件现在已隐藏)
57├── statuses.h                // 错误代码列表
58```
59
60### C++ API
61
62C++ API 存储在 `./include/cpp` 文件夹中,目录结构如下:
63
64```
65include/cpp/
66├── abckit_cpp.h              // C++ API 入口点
67├── headers/
68│   ├── file.h                // 文件操作
69│   ├── graph.h               // 图操作
70│   ├── basic_block.h         // 基本块操作
71│   ├── instruction.h         // 指令操作
72│   ├── literal.h             // 字面量操作
73│   ├── value.h               // 值操作
74│   ├── type.h                // 类型操作
75│   ├── dynamic_isa.h         // 动态 ISA 操作
76│   ├── config.h              // 配置
77│   ├── utils.h               // 工具函数
78│   ├── base_classes.h        // 基础类
79│   ├── base_concepts.h       // 手动实现 concepts 特性
80│   ├── core/                 // 语言无关 API
81│   ├── arkts/                // ArkTS 特定 API
82│   └── js/                   // JS 特定 API
83```
84
85C API 是纯 C 函数,实现存储在 `./src/` 文件夹中并用 C++ 编写。C++ API 提供了更高级的面向对象接口。
86
87## 按组件的控制流
88
891. 调用 `openAbc` 时:
90   1. 将 `abc` 文件读入 `panda_file`
91   2. 使用 `abc2program` 将 `panda_file` 转换为 `pandasm`
922. Abckit 元数据 API 获取/处理 `pandasm` 程序信息
933. 当调用 `createGraphFromFunction` 时:
94   1. `pandasm` 程序信息被转换成 `panda_file`(因为当前的 IR 构建器只支持 `panda_file` 输入)
95   2. IR 构建器为函数构建控制流图: `ark::compiler::Graph`
964. Abckit Graph API 获取/处理 `ark::compiler::Graph`
975. 当调用 `functionSetGraph` 时,代码生成器使用 `ark::compiler::Graph` 生成 `pandasm` 格式的字节码并替换函数的原始字节码
986. 当调用 `writeAbc` 时,转换后的 `pandasm` 程序被写到 abc 文件中
99
100```
101                                                                                ──────────────────────────────────────────────────────────────────────────────────────────────────
102                                                                                |                                                                                                /\
103                                                                                \/                                                                                               |
104x.abc────>(ark/panda)::panda_file───>(ark/panda)::abc2program────>(ark/panda)::pandasm────>(ark/panda)::panda_file───>(ark/panda)::ir_builder────>ark::compiler::Graph──>(ark/panda::)codegen
105                                                                    |            /\              |                                                   /\           |
106                                                                    |             |              |                                                   |            |
107                                                                    |             |              |                                                   |            |
108                                                                (abckit metadata API)            |                                                   |            \/
109                                                                                                 ──────────>(ark/panda)::RuntimeIface───────────────>(abckit IR API)
110```
111
112## 按源文件的控制流
113
1141. 声明 C API
1152. 上述 API 的 C++ 实现主要在动态和静态运行时之间进行分发
1163. 运行时特定实现:
117   1. 动态运行时实现
118   2. 静态运行时实现
1194. API 接收并返回指向不透明 `AbckitXXX` 结构的指针
120
121```
122
123                                                  |───────────────────────────────────────────|
124                                                  |     4. 数据结构(上下文)(./src)            |
125                                                  |  metadata_inspect_impl.h                  |
126                                                  |  ir_impl.h                                |
127                                                  |───────────────────────────────────────────|
128                                                                    /\
129                                                                    |
130                                                                    \/
131───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
132                                                                    /\
133                                                                    |
134                                                                    \/
135  |──────────────────────────────────────|        |───────────────────────────────────────────|        |─────────────────────────────────────────────────────────────────|
136  |     1. API 声明 (./include/c)         |        |     2. API 实现 (./src/)                  |        |     3.1 动态运行时实现 (./src/adapter_dynamic/)                  |
137  |  abckit.h                            |        |  abckit_impl.cpp                          |        |  abckit_dynamic.cpp                                             |
138  |  metadata_core.h                     |        |  metadata_(inspect|modify)_impl.cpp       |        |  metadata_(inspect|modify)_dynamic.cpp                          |
139  |  ir_core.h                           |        |  ir_impl.cpp                              |        |                                                                 |
140  |  extensions/arkts/metadata_arkts.h   |───────>|  metadata_arkts_(inspect|modify)_impl.cpp |───────>|                                                                 |
141  |  extensions/js/metadata_js.h         |        |  metadata_js_(inspect|modify)_impl.cpp    |        |                                                                 |
142  |  isa/isa_dynamic.h                   |        |  isa_dynamic_impl.cpp                     |        |                                                                 |
143  |  isa/isa_static.h                    |        |  isa_static_impl.cpp                      |        |                                                                 |
144  |──────────────────────────────────────|        |───────────────────────────────────────────|        |─────────────────────────────────────────────────────────────────|
145                                                                    |
146                                                                    \/
147                                        |───────────────────────────────────────────────────────────────|
148                                        |     3.2 静态运行时实现 (./src/adapter_static/)                 |
149                                        |  abckit_static.cpp                                            |
150                                        |  metadata_(inspect|modify)_static.cpp                         |
151                                        |  ir_static.cpp                                                |
152                                        |───────────────────────────────────────────────────────────────|
153
154```
155
156## 动态和静态文件格式的处理
157
158许多 API 能够根据 `abc` 文件的源语言处理动态和静态文件格式。
159运行时特定实现存储在 `./src/adapter_dynamic/` 和 `./src/adapter_static/` 中
160
161例如, `functionGetName()` API的实现(`./src/metadata_inspect_impl.cpp`):
162
163```cpp
164    switch (function->module->target) {
165        case ABCKIT_TARGET_JS:
166        case ABCKIT_TARGET_ARK_TS_V1:
167            return FunctionGetNameDynamic(function);
168        case ABCKIT_TARGET_ARK_TS_V2:
169            return FunctionGetNameStatic(function);
170    }
171```
172
173根据函数的源语言调用两个函数之一:
174
175- `FunctionGetNameDynamic()` 适用于动态字节码,代码位于: `./src/adapter_dynamic/metadata_inspect_dynamic.cpp`
176- `FunctionGetNameStatic()` 适用于静态字节码,代码位于: `./src/adapter_static/metadata_inspect_static.cpp`
177
178## 数据结构(上下文)和不透明指针
179
180Abckit C API接收并返回指向不透明 `AbckitXXX` 结构的指针。
181用户有这些结构的前向声明类型,实现对用户隐藏并存储在 `./src/metadata_inspect_impl.h` 中。
182因此,用户只能从 API 接收指针并将其传递给另一个 API,不能手动修改。
183
184例如,这是来自 `./include/c/metadata_core.h` 的前向类型声明:
185
186```
187typedef struct AbckitLiteral AbckitLiteral;
188```
189
190这是来自 `./src/metadata_inspect_impl.h` 的实现:
191
192```
193struct AbckitLiteral {
194    AbckitFile *file;
195    libabckit::pandasm_Literal* val;
196};
197```
198
199## 数据结构(上下文)实现
200
201### 元数据
202
203在 `openAbc` API 调用时,abckit 执行以下步骤:
204
2051. 使用 `panda_file` 打开 `abc` 文件
2062. 使用 `abc2program` 将打开的 panda 文件转换为 `pandasm` 程序
2073. **贪心遍历**所有 `pandasm` 结构并创建相应的 `AbckitXXX` 结构
208
209所有 `AbckitXXX` 数据结构的实现都存储在 `metadata_inspect_impl.h` 和 `ir_core.h` 中。
210顶层数据结构是 `AbckitFile`,用户在 `openAbc` 调用后接收 `AbckitFile*` 指针。
211
212`AbckitXXX` 元数据结构具有"树结构",与源程序结构匹配,例如:
213
2141. `AbckitFile` 拥有 `unique_ptr<AbckitCoreModule>` 的 vector(每个模块通常对应一个源文件)
2152. `AbckitCoreModule` 拥有 `unique_ptr<AbckitCoreNamespace>`(顶层命名空间)、
216   `unique_ptr<AbckitCoreClass>`(顶层类)、`unique_ptr<AbckitCoreFunction>`(顶层函数)的 vector
2173. `AbckitNamespace` 拥有 `unique_ptr<AbckitCoreNamespace>`(命名空间中嵌套的命名空间)、
218   `unique_ptr<AbckitCoreClass>`(命名空间中嵌套的类)、`unique_ptr<AbckitCoreFunction>`(顶层命名空间函数)的 vector
2194. `AbckitCoreClass` 拥有 `unique_ptr<AbckitCoreFunction>`(类方法)的 vector
2205. `AbckitCoreFunction` 拥有 `unique_ptr<AbckitCoreFunction>`(嵌套在其他函数中的函数)的 vector
221
222### 图
223
224在 `createGraphFromFunction` API 调用时,abckit 执行以下步骤:
225
2261. 从 `pandasm` 函数生成 `panda_file`(这是必需的,因为当前 `ir_builder` 只支持 `panda_file` 输入)
2272. 使用 `IrBuilder` 构建 `ark::compiler::Graph`
2283. **贪心遍历 `ark::compiler::Graph` 并创建相应的 `AbckitXXX` 结构**
229
230`AbckitXXX` 图结构是:`AbckitGraph`、`AbckitBasicBlock`、`AbckitInst` 和 `AbckitIrInterface`。
231对于每个 `ark::compiler::Graph` 基本块和指令,创建 `AbckitBasicBlock` 和 `AbckitInst`。
232`AbckitGraph` 包含这样的映射:
233
234```cpp
235std::unordered_map<ark::compiler::BasicBlock *, AbckitBasicBlock *> implToBB;
236std::unordered_map<ark::compiler::Inst *, AbckitInst *> implToInst;
237```
238
239因此我们可以从内部图实现获取相关的 `AbckitXXX` 结构。
240
241## 头文件命名冲突
242
243**重要的实现限制:** libabckit 包含来自动态和静态运行时的头文件,
244因此,在构建期间,clang 必须提供两个运行时文件夹的包含路径(`-I`)。
245但是两个运行时中有很多具有相同名称的文件和文件夹,这会导致 `#include` 的命名冲突。
246这就是 AbcKit 中没有文件同时包含两个运行时头文件的原因:
247- 有 `./src/adapter_dynamic/` 文件夹用于包含动态运行时头文件的文件
248- 有 `./src/adapter_static/` 文件夹用于包含静态运行时头文件的文件
249
250### 包装器(Wrappers)
251
252但对于某些情况,我们需要在单个文件中处理两个运行时,例如:
253
254- 从 `panda::panda_file::Function` 生成 `ark::compiler::Graph` 时
255- 或者从 `ark::compiler::Graph` 生成 `panda::pandasm::Function` 时
256
257对于这种情况,我们使用存储在`./src/wrappers/` 中的**包装器**来处理两个运行时。
258在下图中(箭头显示包含方向),您可以看到:
259
260- `metadata_inspect_dynamic.cpp` 包含动态运行时头文件,并且也使用静态图(通过 `graph_wrapper.h`)
261- `graph_wrapper.cpp` 包含静态运行时头文件,并且也使用动态 `panda_file`(通过 `abcfile_wrapper.h`)
262
263```
264       metadata_inspect_dynamic.cpp ──>graph_wrapper.h<────|
265       |                                                   |
266       \/                                                  |
267DynamicRuntime                                             |<───graph_wrapper.cpp──>StaticRuntime
268       /\                                                  |
269       |                                                   |
270      abcfile_wrapper.cpp────────────>abcfile_wrapper.h<───|
271```
272
273按照上图箭头,可以看到没有文件同时包含静态和动态运行时的头文件
274
275## 字节码 <──> 中间表示 (IR)
276
277abckit 使用 `ark::compiler::Graph` 作为内部图表示,
278因此动态和静态 `pandasm` 字节码都被转换为单个 `IR`
279
280字节码与 IR 的转换方法与字节码优化器相同,
281IR 构建器将字节码转换为 IR,代码生成器将 IR 转换为字节码。
282
283- 有两个 IR 构建器:`libabckit::IrBuilderDynamic` 和 `ark::compiler::IrBuilder`
284- 两个字节码优化器:`libabckit::CodeGenDynamic` 和 `libabckit::CodeGenStatic`
285- 两个运行时接口:`libabckit::AbckitRuntimeAdapterDynamic` 和 `libabckit::AbckitRuntimeAdapterStatic`
286
287运行时接口是静态编译器的一部分,需要抽象出 IR 构建器
288IR 构建器的每个用户都应该提供自己的运行时接口(根据编译器的设计)。
289
290IR 接口(`AbckitIrInterface`)源自字节码优化器,需要存储 `panda_file` 实体名称和偏移量之间的关系。
291IR 接口的实例:
292
2931. 当函数的字节码转换为 IR 时创建
2942. 存储在 `AbckitGraph` 实例中
2953. 在 abckit API 实现中使用,以从指令的立即偏移量获取 `panda_file` 实体
296
297### IR 构建器
298
299对于静态字节码,abckit 重用静态运行时的 IrBuilder。
300
301对于动态字节码,abckit 使用动态运行时 IrBuilder 的分支,并进行多种更改。
302对于动态字节码,大多数指令仅转换为内部调用(例如 `Intrinsic.callthis0`)。
303
304### 代码生成
305
306对于静态字节码,abckit 基于静态运行时的字节码优化器和代码生成器做了多处修改。
307对于动态字节码,abckit 基于动态运行时的字节码优化器和代码生成器做了多处修改。
308
309### 编译器传递
310
311在图创建和字节码生成期间,应用了额外的图清理和优化,
312因此如果您这样做:`graph1`->`bytecode`->`graph2` 而不进行任何额外更改,
313`graph1` **可能与** `graph2` 存在差异。