- 添加 C++ 模版实现动态语言强类型数据容器的专利文档 - 添加混合态编程语言编译执行方法的专利文档 - 文档涵盖技术方案、系统组成、方法流程和关键保护点 - 包含详细的术语解释和技术背景说明pull/1/head
parent
efd6beac87
commit
7ee2a161b9
3 changed files with 860 additions and 0 deletions
@ -0,0 +1,406 @@ |
||||
# 专利申请技术交底书:一种利用 C++ 模版实现动态语言强类型数据容器的方法 |
||||
|
||||
> 本文档为专利申请技术交底草案,面向专利代理人说明技术方案。文中“本发明”指“一种利用 C++ 模版实现动态语言强类型数据容器的方法”。本文档不构成法律意见,正式权利要求应由专利代理人结合检索结果进一步撰写。 |
||||
|
||||
## 1. 技术应用产品 |
||||
|
||||
本发明应用于 Swoole-Compiler PHP AOT 编译器。该产品用于将 PHP 动态语言程序预先编译为 C++ 本地代码、PHP 扩展或可执行程序,并在编译后的程序中保留 PHP 运行时兼容能力。 |
||||
|
||||
本发明重点解决动态语言中数组和容器结构类型不确定、运行时开销高、难以利用 C++ 静态类型优化的问题。该方案通过在动态语言语法层引入强类型容器声明,并在 AOT 编译阶段将其转换为 C++ 模版容器实例,使动态语言程序能够在局部性能热点中获得接近静态语言的数据结构性能,同时维持与动态语言数组之间的互操作能力。 |
||||
|
||||
## 2. 术语解释 |
||||
|
||||
| 术语 | 中文说明 | |
||||
| --- | --- | |
||||
| PHP | 一种动态类型脚本语言 | |
||||
| AOT | Ahead-Of-Time,预先编译,指程序运行前先编译为目标代码 | |
||||
| C++ 模版 | C++ Template,一种在编译期生成强类型代码的机制 | |
||||
| 动态语言 | 变量类型和函数调用目标可在运行时变化的语言 | |
||||
| 强类型容器 | key、value、长度、嵌套结构或类约束在编译期明确的容器 | |
||||
| PHP Array | PHP 语言内建数组,兼具列表、字典、哈希表等语义 | |
||||
| zval | PHP 运行时保存任意类型值的内部结构 | |
||||
| HashTable | PHP Array 的常见底层哈希表结构 | |
||||
| AST | Abstract Syntax Tree,抽象语法树 | |
||||
| 元信息 | 编译器记录的容器种类、类型、维度、C++ 声明等信息 | |
||||
| 类型标识 | 用于区分不同强类型容器结构的整数标识 | |
||||
| UnsafePtr | 携带容器指针和类型标识的受控指针封装 | |
||||
|
||||
## 3. 技术背景及现有技术方案 |
||||
|
||||
### 3.1 大的技术背景 |
||||
|
||||
动态语言的优势在于开发灵活。以 PHP 为例,同一个变量可以在不同位置保存整数、浮点数、字符串、数组或对象。同一个 PHP Array 既可以作为连续列表,也可以作为字符串 key 的字典,还可以同时混合整数 key、字符串 key 和不同类型 value。 |
||||
|
||||
例如: |
||||
|
||||
```php |
||||
$data = []; |
||||
$data[] = 1; |
||||
$data["name"] = "swoole"; |
||||
$data[10] = new stdClass(); |
||||
``` |
||||
|
||||
这种设计降低了业务开发门槛,但也导致编译器很难在编译期确定数据结构的真实形状。对于 AOT 编译器而言,如果无法确定数组元素类型、key 类型、长度和嵌套结构,就只能保守地生成通用动态容器代码,无法充分利用 C++ 的静态类型和模版优化能力。 |
||||
|
||||
与之相对,C++、Rust、Go 等静态语言通常要求容器类型明确,例如 `std::vector<int>`、`std::array<double, 100>`。这类容器在编译期即可确定元素大小、访问方式和内存布局,因此访问路径短,编译器可进一步进行内联、寄存器分配和循环优化。 |
||||
|
||||
本发明试图在动态语言和静态语言之间建立一种局部强类型数据容器机制,使动态语言代码仍保持类似数组的写法,但在编译期被转换为 C++ 模版容器。 |
||||
|
||||
### 3.2 小的技术背景 |
||||
|
||||
Swoole-Compiler 是一种 PHP AOT 编译器。它将 PHP 源文件解析为抽象语法树,再生成 C++ 代码并编译为 PHP 扩展或二进制程序。对于普通 PHP 变量,编译器可使用 `php::Var`、`php::Array` 等运行时封装表示动态语义。 |
||||
|
||||
但是,对于高频数组访问、数值计算、固定长度缓冲区、映射表、对象集合等场景,继续使用普通 PHP Array 会带来以下开销: |
||||
|
||||
- key 和 value 都需要动态类型判断; |
||||
- 每个 value 通常需要通过 zval 表示; |
||||
- 哈希查找、引用计数、写时复制等机制增加运行时路径; |
||||
- 内存布局不连续,CPU 缓存利用率较差; |
||||
- 编译器难以确认数组中是否只保存某一种类型; |
||||
- 跨函数传递大型容器时容易产生复制或动态封装开销。 |
||||
|
||||
因此,需要一种适合 AOT 编译器的强类型容器表达、检查和代码生成方案。 |
||||
|
||||
### 3.3 最相近的现有技术方案 |
||||
|
||||
现有技术大致包括以下几类: |
||||
|
||||
1. **全部使用 PHP Array 的动态容器方案** |
||||
所有数组均由 PHP 运行时 HashTable 和 zval 表示。该方案兼容性好,但性能受动态类型和哈希结构限制。 |
||||
|
||||
2. **用户手写 C++ 扩展方案** |
||||
开发者在 C++ 中手写 `std::vector`、`std::map` 等结构,并通过 PHP 扩展函数暴露给 PHP。该方案性能高,但开发成本高,且用户需要手动维护 PHP 与 C++ 的类型映射。 |
||||
|
||||
3. **通用 JIT 或 AOT 类型推断方案** |
||||
编译器尝试根据上下文推断 PHP Array 的元素类型。但 PHP Array 的动态写入、动态 key、函数参数和返回值会导致推断不稳定,通常只能在非常局部的场景中优化。 |
||||
|
||||
4. **PHP 用户态容器类方案** |
||||
例如通过对象类封装数组或特定数据结构。该方案改善了接口规范,但底层仍可能依赖 PHP 对象、zval 和动态方法调用,难以达到 C++ 模版容器级别的性能。 |
||||
|
||||
## 4. 现有技术缺点及本发明目的 |
||||
|
||||
### 4.1 现有技术缺点 |
||||
|
||||
现有方案存在以下缺点: |
||||
|
||||
1. 动态数组类型不确定,导致编译器无法稳定生成强类型目标代码。 |
||||
2. 普通 PHP Array 底层结构过于通用,高频访问时存在哈希查找和动态类型开销。 |
||||
3. 手写 C++ 扩展需要用户理解 PHP 扩展开发、内存管理和类型转换,开发门槛高。 |
||||
4. 通用类型推断难以表达固定长度、嵌套维度、key 类型、value 类约束等完整容器信息。 |
||||
5. 强类型容器与 PHP Array 之间缺少统一互操作规则,容易在性能与兼容性之间割裂。 |
||||
6. 容器引用跨函数传递时,如果直接暴露 C++ 指针,会产生类型误用和内存安全风险。 |
||||
|
||||
### 4.2 本发明目的 |
||||
|
||||
本发明的目的在于提供一种利用 C++ 模版实现动态语言强类型数据容器的方法,使动态语言程序在局部代码中可以声明强类型容器,由编译器生成 C++ 模版容器代码,并在必要时自动与动态语言数组互相转换。 |
||||
|
||||
进一步地,本发明还提供一种携带类型标识的容器引用传递机制,使强类型容器在 Native 函数之间能够低拷贝传递,并在运行时进行类型一致性校验。 |
||||
|
||||
## 5. 本发明技术方案 |
||||
|
||||
### 5.1 总体方案 |
||||
|
||||
本发明在动态语言中定义一组强类型容器构造语法,例如: |
||||
|
||||
```php |
||||
$a = std::array(native_types::type_int, 100); |
||||
$v = std::vector(native_types::type_float); |
||||
$m = std::map(complex_types::type_str, native_types::type_int); |
||||
$h = std::unordered_map(native_types::type_int, User::class); |
||||
``` |
||||
|
||||
编译器在 AOT 阶段识别这些构造表达式,生成容器元信息,并将其转换为 C++ 模版实例: |
||||
|
||||
```cpp |
||||
php::StdArray<php::Int, 100> a{}; |
||||
php::StdVector<php::Float> v{}; |
||||
php::StdMap<php::Str, php::Int> m{}; |
||||
php::StdUnorderedMap<php::Int, php::Object> h{}; |
||||
``` |
||||
|
||||
编译器后续在下标访问、赋值、遍历、函数传参和类型转换时均使用该元信息进行静态检查和代码生成。 |
||||
|
||||
### 5.2 系统组成 |
||||
|
||||
```text |
||||
图 1:系统组成图 |
||||
|
||||
PHP 源码输入模块 |
||||
| |
||||
v |
||||
抽象语法树解析模块 |
||||
| |
||||
v |
||||
强类型容器识别模块 |
||||
| |
||||
v |
||||
容器元信息构建模块 |
||||
| |
||||
+--> 类型标识注册模块 |
||||
| |
||||
+--> 下标访问代码生成模块 |
||||
| |
||||
+--> 赋值与 copy 判定模块 |
||||
| |
||||
+--> PHP Array 互操作模块 |
||||
| |
||||
+--> UnsafePtr 自动装箱与校验模块 |
||||
| |
||||
v |
||||
C++ 模版代码生成模块 |
||||
| |
||||
v |
||||
C++ 编译器 |
||||
| |
||||
v |
||||
PHP 扩展或二进制程序 |
||||
``` |
||||
|
||||
各模块说明如下: |
||||
|
||||
- PHP 源码输入模块:读取动态语言源文件。 |
||||
- 抽象语法树解析模块:将源码解析为语法树节点。 |
||||
- 强类型容器识别模块:识别 `std::array` 等容器构造表达式。 |
||||
- 容器元信息构建模块:记录容器的种类、key 类型、value 类型、类约束、维度等。 |
||||
- 类型标识注册模块:为每一种容器结构生成可比较的类型标识。 |
||||
- 下标访问代码生成模块:根据容器类型生成数组访问、边界检查、key 转换代码。 |
||||
- 赋值与 copy 判定模块:判断是 C++ 容器 copy,还是转换为 PHP Array。 |
||||
- PHP Array 互操作模块:在动态语义边界生成 `php::toArray()`。 |
||||
- UnsafePtr 自动装箱与校验模块:在函数调用边界生成带类型标识的容器指针封装。 |
||||
- C++ 模版代码生成模块:输出强类型 C++ 模版容器代码。 |
||||
|
||||
### 5.3 方法流程 |
||||
|
||||
```text |
||||
图 2:方法流程图 |
||||
|
||||
步骤 S1:解析动态语言源代码,获得抽象语法树; |
||||
步骤 S2:识别强类型容器构造表达式; |
||||
步骤 S3:解析容器种类、key 类型、value 类型、类约束和维度; |
||||
步骤 S4:生成容器元信息,并登记类型标识; |
||||
步骤 S5:在变量表中记录该变量为强类型容器; |
||||
步骤 S6:遇到下标访问时,根据容器元信息生成强类型访问代码; |
||||
步骤 S7:遇到赋值时,判断左右两侧是否为相同强类型容器; |
||||
步骤 S8:相同则生成 C++ 容器 copy,不相同则按规则报错或转 PHP Array; |
||||
步骤 S9:遇到 Native 函数 UnsafePtr 参数时,自动装箱容器指针和类型标识; |
||||
步骤 S10:被调用端解箱时校验类型标识,一致则返回 C++ 引用,不一致则抛出异常。 |
||||
``` |
||||
|
||||
### 5.4 容器元信息 |
||||
|
||||
容器元信息至少包括以下字段: |
||||
|
||||
```text |
||||
kind:容器种类,例如 array、vector、map、unordered_map; |
||||
decl:目标 C++ 模版声明; |
||||
type:value 的 C++ 类型; |
||||
class:value 为对象时的类名; |
||||
keyType:map 或 unordered_map 的 key 类型; |
||||
sizes:std::array 的维度数组; |
||||
bytes:std::array 的预计内存大小; |
||||
typeId:根据上述字段生成的类型标识。 |
||||
``` |
||||
|
||||
例如: |
||||
|
||||
```php |
||||
$b = std::array(std::array(native_types::type_int, 3), 2); |
||||
``` |
||||
|
||||
对应元信息可以表示为: |
||||
|
||||
```text |
||||
kind=array |
||||
decl=php::StdArray<php::StdArray<php::Int, 3>, 2> |
||||
type=php::Int |
||||
sizes=[3, 2] |
||||
bytes=2 * 3 * sizeof(php::Int) |
||||
typeId=自动分配的整数 |
||||
``` |
||||
|
||||
### 5.5 std::array 嵌套类型推导 |
||||
|
||||
`std::array` 支持嵌套结构。本发明根据访问层级推导子数组类型。 |
||||
|
||||
示例: |
||||
|
||||
```php |
||||
$a = std::array(native_types::type_int, 3); |
||||
$b = std::array(std::array(native_types::type_int, 3), 2); |
||||
$a = $b[1]; |
||||
``` |
||||
|
||||
处理方法: |
||||
|
||||
1. 编译器读取 `$b` 的维度信息 `[2, 3]`。 |
||||
2. 解析 `$b[1]` 的访问层级为 1。 |
||||
3. 计算剩余维度 `[3]`。 |
||||
4. 推导 `$b[1]` 的类型为 `std::array<int, 3>`。 |
||||
5. 与 `$a` 的类型比较。 |
||||
6. 如果完全一致,生成 C++ copy: |
||||
|
||||
```cpp |
||||
a = b[php::safeIndex(php::toInt(1L), 2)]; |
||||
``` |
||||
|
||||
这里 `safeIndex` 表示边界检查函数。它确保动态语言下标访问仍具备越界检查语义。 |
||||
|
||||
### 5.6 同类型 copy 与动态数组转换 |
||||
|
||||
本发明将赋值分为两类: |
||||
|
||||
第一类,左值为强类型容器且右值为完全相同强类型容器: |
||||
|
||||
```php |
||||
$a = std::vector(native_types::type_int); |
||||
$b = std::vector(native_types::type_int); |
||||
$a = $b; |
||||
``` |
||||
|
||||
生成: |
||||
|
||||
```cpp |
||||
a = b; |
||||
``` |
||||
|
||||
第二类,左值为普通动态变量,右值为强类型容器: |
||||
|
||||
```php |
||||
$arr = $a; |
||||
``` |
||||
|
||||
生成: |
||||
|
||||
```cpp |
||||
arr = php::toArray(a); |
||||
``` |
||||
|
||||
该规则使强类型容器在强类型区域中保持 C++ 性能,在流入动态语言区域时自动变为普通 PHP Array。 |
||||
|
||||
### 5.7 下标访问和写入 |
||||
|
||||
对于 `std::vector`: |
||||
|
||||
```php |
||||
$v[] = 1; |
||||
$v[0] = 2; |
||||
``` |
||||
|
||||
生成类似: |
||||
|
||||
```cpp |
||||
v.push_back(php::toInt(1L)); |
||||
v.offsetSet(php::toInt(0L), php::toInt(2L)); |
||||
``` |
||||
|
||||
对于 `std::map`: |
||||
|
||||
```php |
||||
$m["x"] = 10; |
||||
``` |
||||
|
||||
生成类似: |
||||
|
||||
```cpp |
||||
m.offsetSet(php::toString("x"), php::toInt(10L)); |
||||
``` |
||||
|
||||
对于类类型 value: |
||||
|
||||
```php |
||||
$v = std::vector(User::class); |
||||
$v[] = new User(); |
||||
``` |
||||
|
||||
编译器检查写入对象是否为指定类,避免错误对象混入容器。 |
||||
|
||||
### 5.8 foreach 遍历 |
||||
|
||||
强类型容器遍历被编译为 C++ 迭代器循环: |
||||
|
||||
```php |
||||
foreach ($v as $i => $value) { |
||||
// ... |
||||
} |
||||
``` |
||||
|
||||
生成类似: |
||||
|
||||
```cpp |
||||
for (auto it = v.begin(); it != v.end(); ++it) { |
||||
i = it - v.begin(); |
||||
value = *it; |
||||
} |
||||
``` |
||||
|
||||
对于 map 类型,key 从 `it->first` 获取,value 从 `it->second` 获取。 |
||||
|
||||
### 5.9 UnsafePtr 自动装箱与类型校验 |
||||
|
||||
为支持容器在 Native 函数之间低拷贝传递,本发明设置 `UnsafePtr` 参数机制。 |
||||
|
||||
用户代码: |
||||
|
||||
```php |
||||
function update(UnsafePtr $ptr): void |
||||
{ |
||||
$v = std::unsafe_cast(std::vector(native_types::type_int), $ptr); |
||||
$v[0] = 100; |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$v = std::vector(native_types::type_int, 1); |
||||
update($v); |
||||
} |
||||
``` |
||||
|
||||
调用端生成: |
||||
|
||||
```cpp |
||||
php_update(php_create_unsafe_ptr(&v, typeId)); |
||||
``` |
||||
|
||||
被调用端生成: |
||||
|
||||
```cpp |
||||
auto &v = php_unsafe_cast<php::StdVector<php::Int>>(ptr, typeId); |
||||
``` |
||||
|
||||
其中 `UnsafePtr` 保存: |
||||
|
||||
```cpp |
||||
void *ptr; |
||||
uint32_t type_id; |
||||
``` |
||||
|
||||
解箱时比较 `type_id`,一致才返回 C++ 引用,不一致则抛出类型异常。这样可避免将 `std::vector<int>` 错误转换为 `std::vector<float>`。 |
||||
|
||||
## 6. 关键点和欲保护点 |
||||
|
||||
1. 在动态语言 AOT 编译过程中识别强类型容器构造语法,并转换为 C++ 模版容器实例。 |
||||
2. 使用容器元信息表统一记录容器种类、C++ 声明、key 类型、value 类型、类约束、维度、内存大小和类型标识。 |
||||
3. 对嵌套 `std::array` 根据访问层级推导子数组类型,并支持子数组与同类型容器之间的 C++ copy。 |
||||
4. 根据左右值容器元信息判断赋值语义:完全相同则生成 C++ copy,否则转为动态数组或编译期报错。 |
||||
5. 对下标访问生成 C++ 强类型访问代码,并保留动态语言的边界检查或 key 类型转换语义。 |
||||
6. 对 foreach 生成 C++ 迭代器循环,同时保持动态语言 key/value 遍历形式。 |
||||
7. 在 Native 函数调用边界根据 ArgInfo 自动将强类型容器装箱为携带类型标识的 UnsafePtr。 |
||||
8. 解箱时基于类型标识进行运行时校验,校验通过后返回 C++ 容器引用。 |
||||
|
||||
## 7. 与现有技术相比的优点 |
||||
|
||||
本发明相比普通 PHP Array 方案,能够在编译期确定容器结构和元素类型,生成 C++ 模版实例,从而减少动态类型判断、哈希查找和 zval 包装开销。 |
||||
|
||||
本发明相比手写 C++ 扩展方案,开发者仍使用接近 PHP 数组的语法,容器声明、类型校验、下标访问、copy、遍历、动态数组转换和跨函数引用传递均由编译器自动完成,降低开发门槛。 |
||||
|
||||
本发明相比普通类型推断方案,不依赖猜测 PHP Array 的使用方式,而是通过显式强类型容器语法建立稳定的类型元信息,使编译结果更可预测。 |
||||
|
||||
## 8. 可选实施方式 |
||||
|
||||
本发明不限于 PHP 语言,也可用于 Python、JavaScript、Ruby 等动态语言的 AOT 编译器。只要动态语言编译器能够识别强类型容器声明,并生成 C++、Rust、Go 或其他静态语言目标代码,均可采用类似技术方案。 |
||||
|
||||
本发明中的 C++ 模版容器也不限于 `StdArray`、`StdVector`、`StdMap`、`StdUnorderedMap`,可扩展为队列、集合、环形缓冲区、矩阵、张量等强类型容器。 |
||||
|
||||
## 9. 保密说明 |
||||
|
||||
本文档涉及 Swoole-Compiler 的编译器内部实现、强类型容器元信息设计、UnsafePtr 类型标识机制和代码生成策略。正式申请前建议作为内部技术资料管理。 |
||||
@ -0,0 +1,453 @@ |
||||
# 专利申请技术交底书:一种混合态编程语言的编译执行方法及系统 |
||||
|
||||
> 本文档为专利申请技术交底草案,面向专利代理人说明技术方案。文中“本发明”指“一种混合态编程语言的编译执行方法及系统”。本文档不构成法律意见,正式权利要求应由专利代理人结合检索结果进一步撰写。 |
||||
|
||||
## 1. 技术应用产品 |
||||
|
||||
本发明应用于 Swoole-Compiler PHP AOT 编译器。Swoole-Compiler 并非简单地将 PHP 完全静态化,也不是传统意义上的纯解释器或纯即时编译器,而是一种“混合态编程语言编译执行系统”。 |
||||
|
||||
在该系统中,同一份 PHP 程序可以同时包含: |
||||
|
||||
- 可被静态分析和预先编译的静态态代码; |
||||
- 需要保留 PHP 动态语义的动态态代码; |
||||
- 静态态与动态态之间的边界转换代码; |
||||
- 可作为 PHP 扩展被动态运行时调用的入口; |
||||
- 可作为独立二进制程序执行的入口。 |
||||
|
||||
该系统使动态语言具备静态语言的性能优势,同时保留动态语言的灵活优势。 |
||||
|
||||
## 2. 术语解释 |
||||
|
||||
| 术语 | 中文说明 | |
||||
| --- | --- | |
||||
| 混合态 | 同一程序中同时存在静态编译态和动态解释态,并可在两种状态之间切换 | |
||||
| 静态态 | 编译器可在编译期确定类型、函数、方法、属性或控制路径的状态 | |
||||
| 动态态 | 需要在运行时依据 PHP 语义解析类型、函数、方法或属性的状态 | |
||||
| AOT | Ahead-Of-Time,预先编译 | |
||||
| VM | Virtual Machine,虚拟机,这里指 PHP Zend VM | |
||||
| Native 函数 | 被 AOT 编译为 C++ 函数的 PHP 函数或方法 | |
||||
| 动态调用 | 运行时根据函数名、方法名、对象类型或回调对象查找并调用目标 | |
||||
| 静态直连 | 编译期确定调用目标后生成 C++ 直接函数调用 | |
||||
| ArgInfo | 参数信息,包括类型、默认值、引用、变长参数等 | |
||||
| 符号表 | 编译器记录函数、类、接口、trait、常量、属性、方法等信息的数据结构 | |
||||
| 包装函数 | 将 Zend VM 调用入口转换为 Native 函数调用的桥接函数 | |
||||
| 回退 | 当静态分析不能保证语义正确时,退回动态运行时路径 | |
||||
|
||||
## 3. 技术背景及现有技术方案 |
||||
|
||||
### 3.1 大的技术背景 |
||||
|
||||
传统编程语言通常可分为两类。 |
||||
|
||||
第一类是静态编译语言,例如 C、C++、Go、Rust。它们在运行前完成编译,类型、函数签名和内存布局大多在编译期确定,因此运行性能高。但这类语言通常开发灵活性较弱,动态加载、动态方法调用、运行时修改数据结构等能力有限。 |
||||
|
||||
第二类是动态解释语言,例如 PHP、Python、Ruby、JavaScript。它们在运行时解析变量类型、函数调用、对象属性和方法分派,因此开发效率高、表达灵活。但这类语言通常需要虚拟机、解释器、动态类型判断和运行时查找,性能不如静态编译语言。 |
||||
|
||||
现有 JIT 技术试图在运行时将热点代码编译为机器码,但 JIT 仍依赖运行时采样、类型反馈和热点判断,且难以在部署前得到完全确定的本地代码。传统 AOT 技术则倾向于将程序全部静态化,但面对动态语言的变量函数、动态方法、魔术方法、反射、动态属性、闭包和回调时容易丢失语言语义。 |
||||
|
||||
### 3.2 小的技术背景 |
||||
|
||||
Swoole-Compiler 面向 PHP 程序。PHP 程序具有以下动态特征: |
||||
|
||||
- 变量可以保存任意类型; |
||||
- 函数和方法可以通过字符串或数组形式动态调用; |
||||
- 对象可通过 `__call()`、`__get()`、`__set()` 等魔术方法处理动态行为; |
||||
- 命名空间、use 别名、trait、继承、方法重写会影响真实调用目标; |
||||
- 参数支持默认值、命名参数、变长参数、引用参数; |
||||
- PHP 内置函数和用户函数可混合调用; |
||||
- 程序既可能作为 PHP 扩展运行,也可能作为独立二进制程序运行。 |
||||
|
||||
如果编译器强行将所有 PHP 代码转换为静态 C++ 调用,会破坏上述动态语义。如果完全保留动态解释执行,则无法获得 AOT 的性能优势。 |
||||
|
||||
因此,需要一种新的混合态编程语言设计方案:在可静态确定的区域进入静态态,在不可静态确定的区域进入动态态,并通过统一边界机制实现两种状态的互通。 |
||||
|
||||
### 3.3 最相近的现有技术方案 |
||||
|
||||
现有技术包括: |
||||
|
||||
1. **纯解释执行方案** |
||||
PHP 源码由 Zend VM 解释执行。该方案兼容性强,但每次函数调用、属性访问、数组操作都依赖运行时动态机制。 |
||||
|
||||
2. **纯静态编译方案** |
||||
将源程序整体转换为 C/C++ 或机器码。该方案性能高,但对于动态语言特性支持困难,通常需要限制大量语法或改变语言语义。 |
||||
|
||||
3. **JIT 即时编译方案** |
||||
运行时根据热点路径和类型反馈进行编译。该方案可提升热点性能,但仍需要解释器协作,且编译结果依赖运行时状态。 |
||||
|
||||
4. **手写扩展或 FFI 方案** |
||||
通过 C/C++ 扩展或外部函数接口让动态语言调用静态代码。该方案可以局部提升性能,但静态代码与动态代码之间缺乏统一语言级编译模型。 |
||||
|
||||
## 4. 现有技术缺点及本发明目的 |
||||
|
||||
### 4.1 现有技术缺点 |
||||
|
||||
现有方案存在以下问题: |
||||
|
||||
1. 纯解释执行无法充分利用静态类型和本地代码性能。 |
||||
2. 纯静态编译难以兼容动态语言的动态调用、魔术方法、动态属性和反射等特性。 |
||||
3. JIT 依赖运行时热点和类型反馈,部署前难以得到稳定可预测的编译产物。 |
||||
4. 手写扩展需要开发者显式维护动态语言与静态语言之间的接口、类型转换和生命周期。 |
||||
5. 动态语言中的函数、类、属性和方法查找通常依赖字符串,重复查找成本较高。 |
||||
6. 传统编译器往往以“能否完全静态化”为判断标准,缺少一种表达同一程序内多种执行状态共存的语言级模型。 |
||||
|
||||
### 4.2 本发明目的 |
||||
|
||||
本发明的目的在于提供一种混合态编程语言的编译执行方法及系统,使同一动态语言程序能够被划分为静态态和动态态: |
||||
|
||||
- 在静态态中,编译器生成 C++ 直接调用、强类型变量、强类型容器和本地代码; |
||||
- 在动态态中,系统保留 PHP VM 的动态查找、动态调用、动态属性、回调和通用 zval 语义; |
||||
- 在两种状态之间,通过 ArgInfo、包装函数、符号缓存、类型转换和动态回退机制实现互通。 |
||||
|
||||
由此实现静态语言的性能优势和动态语言的灵活优势兼得。 |
||||
|
||||
## 5. 本发明技术方案 |
||||
|
||||
### 5.1 混合态语言模型 |
||||
|
||||
本发明提出“混合态”语言模型。该模型不是简单地把动态语言编译成静态语言,而是在编译器和运行时共同支持下,将程序中的语句、表达式、函数、方法、变量和调用划分为不同状态。 |
||||
|
||||
混合态至少包括: |
||||
|
||||
1. **静态函数态**:函数定义、参数类型和返回类型可确定,生成 C++ Native 函数。 |
||||
2. **静态对象态**:对象变量的类可确定,方法调用可直连到 C++ 函数。 |
||||
3. **静态数据态**:变量可映射为 C++ 原生类型或 C++ 模版容器。 |
||||
4. **动态值态**:变量使用 `php::Var`、zval 或 PHP 对象保存,保留动态类型语义。 |
||||
5. **动态调用态**:函数名、方法名或对象类型无法确定时,通过 PHP 运行时调用。 |
||||
6. **边界桥接态**:静态态与动态态之间进行参数提取、类型转换、返回值写回和符号缓存。 |
||||
|
||||
### 5.2 系统组成 |
||||
|
||||
```text |
||||
图 1:混合态编程语言系统组成图 |
||||
|
||||
PHP 源码 / 项目配置 |
||||
| |
||||
v |
||||
预处理与符号提取模块 |
||||
| |
||||
v |
||||
依赖排序与语义分析模块 |
||||
| |
||||
v |
||||
混合态判定模块 |
||||
| |
||||
+--> 静态态代码生成模块 |
||||
| | |
||||
| +--> C++ 函数直连 |
||||
| +--> C++ 原生类型 |
||||
| +--> C++ 模版容器 |
||||
| |
||||
+--> 动态态代码生成模块 |
||||
| | |
||||
| +--> PHP VM 动态调用 |
||||
| +--> zval / php::Var 动态值 |
||||
| +--> 魔术方法和回调 |
||||
| |
||||
+--> 边界桥接模块 |
||||
| |
||||
+--> ArgInfo 参数转换 |
||||
+--> Zend 包装函数 |
||||
+--> 符号缓存 |
||||
+--> 动态回退 |
||||
| |
||||
v |
||||
C++ 源码与扩展注册代码 |
||||
| |
||||
v |
||||
PHP 扩展或可执行二进制 |
||||
``` |
||||
|
||||
### 5.3 方法流程 |
||||
|
||||
```text |
||||
图 2:混合态编译执行流程图 |
||||
|
||||
步骤 S1:读取 PHP 源文件和项目配置; |
||||
步骤 S2:解析抽象语法树; |
||||
步骤 S3:提取函数、类、接口、trait、常量、属性、方法等符号; |
||||
步骤 S4:根据符号使用关系对文件进行依赖排序; |
||||
步骤 S5:解析函数和方法的 ArgInfo; |
||||
步骤 S6:对每个表达式或调用点判断是否可进入静态态; |
||||
步骤 S7:若目标、类型和参数可确定,则生成 C++ 静态直连代码; |
||||
步骤 S8:若存在动态语义风险,则生成动态态调用代码; |
||||
步骤 S9:为静态态与动态态边界生成参数转换、返回值转换和包装函数; |
||||
步骤 S10:为函数、类、方法、属性生成运行时缓存映射; |
||||
步骤 S11:编译 C++ 代码,生成 PHP 扩展或可执行程序; |
||||
步骤 S12:运行时根据生成代码执行静态直连或动态回退路径。 |
||||
``` |
||||
|
||||
### 5.4 预处理与符号提取 |
||||
|
||||
编译器在正式生成 C++ 代码前,先扫描 PHP 源码,提取: |
||||
|
||||
- 函数定义; |
||||
- 类定义; |
||||
- 接口定义; |
||||
- trait 定义; |
||||
- 类属性; |
||||
- 类方法; |
||||
- 类常量; |
||||
- 全局常量; |
||||
- 命名空间和 use 别名; |
||||
- 函数、类、方法、常量的使用关系。 |
||||
|
||||
随后构建符号依赖图,并对源文件进行拓扑排序。这样可提高静态分析成功率,避免因为文件顺序导致函数或类暂不可见。 |
||||
|
||||
### 5.5 ArgInfo 统一参数模型 |
||||
|
||||
本发明使用 ArgInfo 描述函数和方法参数,包括: |
||||
|
||||
```text |
||||
参数名称; |
||||
参数类型; |
||||
对象类名; |
||||
是否引用参数; |
||||
是否变长参数; |
||||
是否可空; |
||||
默认值; |
||||
是否为 UnsafePtr; |
||||
是否为构造器属性提升参数。 |
||||
``` |
||||
|
||||
ArgInfo 同时服务于两个方向: |
||||
|
||||
1. **AOT 内部直连调用**:编译器根据 ArgInfo 重排命名参数、填充默认值、合并变长参数并生成 C++ 直接调用。 |
||||
2. **Zend 运行时入口调用**:当编译后函数作为 PHP 扩展函数被 PHP VM 调用时,包装函数根据 ArgInfo 从调用栈读取参数并转换类型。 |
||||
|
||||
该设计使静态态和动态态共享同一套参数语义。 |
||||
|
||||
### 5.6 静态态代码生成 |
||||
|
||||
当编译器能够确定调用目标时,生成 C++ 直接调用。 |
||||
|
||||
示例: |
||||
|
||||
```php |
||||
function add(int $a, int $b): int |
||||
{ |
||||
return $a + $b; |
||||
} |
||||
|
||||
add(1, 2); |
||||
``` |
||||
|
||||
生成类似: |
||||
|
||||
```cpp |
||||
php_add(php::toInt(1L), php::toInt(2L)); |
||||
``` |
||||
|
||||
对于对象方法: |
||||
|
||||
```php |
||||
$obj->run($arg); |
||||
``` |
||||
|
||||
如果 `$obj` 的类可确定,且不存在方法重写或动态魔术方法风险,则生成: |
||||
|
||||
```cpp |
||||
php_Class_run(obj, converted_arg); |
||||
``` |
||||
|
||||
静态态还包括: |
||||
|
||||
- `int`、`float`、`bool` 等原生类型; |
||||
- `std::array`、`std::vector` 等 C++ 模版容器; |
||||
- 可确定类的对象属性访问; |
||||
- 可确定函数的默认参数和变长参数处理; |
||||
- 编译期可确定的常量和类常量访问。 |
||||
|
||||
### 5.7 动态态代码生成 |
||||
|
||||
当出现以下情况时,编译器进入动态态: |
||||
|
||||
- 函数名来自变量; |
||||
- 方法名来自变量; |
||||
- 对象真实类型无法确定; |
||||
- 类可能存在 `__call()` 魔术方法; |
||||
- 方法被子类重写,静态直连可能改变动态分派语义; |
||||
- 需要调用 PHP 内置动态函数; |
||||
- 回调、闭包或占位符表达式无法完全静态确定; |
||||
- 变量使用通用 `mixed` 或动态数组语义。 |
||||
|
||||
动态态生成类似: |
||||
|
||||
```cpp |
||||
php::call(function_ptr, arg_list); |
||||
``` |
||||
|
||||
或: |
||||
|
||||
```cpp |
||||
object.call(method_ptr, arg_list); |
||||
``` |
||||
|
||||
动态态保持 PHP VM 的函数查找、方法分派、zval 类型和动态回调语义。 |
||||
|
||||
### 5.8 静态直连与动态回退判定 |
||||
|
||||
本发明不要求所有代码都静态化,而是在每个调用点执行判定。 |
||||
|
||||
```text |
||||
图 3:调用点状态判定流程 |
||||
|
||||
调用表达式 |
||||
| |
||||
v |
||||
函数名或方法名是否为字面量? |
||||
| |
||||
+-- 否 --> 动态态调用 |
||||
| |
||||
+-- 是 |
||||
| |
||||
v |
||||
是否可在符号表中找到 Native 目标? |
||||
| |
||||
+-- 否 --> 动态态调用 |
||||
| |
||||
+-- 是 |
||||
| |
||||
v |
||||
对象类或函数签名是否可确定? |
||||
| |
||||
+-- 否 --> 动态态调用 |
||||
| |
||||
+-- 是 |
||||
| |
||||
v |
||||
是否存在魔术方法、重写、动态回调等风险? |
||||
| |
||||
+-- 是 --> 动态态调用 |
||||
| |
||||
+-- 否 --> 静态态直连 |
||||
``` |
||||
|
||||
该机制使语言运行时不是单一状态,而是按代码位置自动选择最佳状态。 |
||||
|
||||
### 5.9 边界桥接机制 |
||||
|
||||
静态态和动态态之间通过边界桥接机制互通。 |
||||
|
||||
#### 5.9.1 动态调用静态函数 |
||||
|
||||
当 PHP VM 调用编译后的函数时,进入 Zend 包装函数: |
||||
|
||||
```text |
||||
Zend 调用入口 |
||||
| |
||||
v |
||||
读取调用栈参数 |
||||
| |
||||
v |
||||
根据 ArgInfo 转换参数 |
||||
| |
||||
v |
||||
调用 Native 函数 |
||||
| |
||||
v |
||||
将返回值写回 return_value |
||||
``` |
||||
|
||||
#### 5.9.2 静态代码调用动态函数 |
||||
|
||||
当 AOT 代码无法确定目标时,生成动态调用: |
||||
|
||||
```text |
||||
C++ 静态代码 |
||||
| |
||||
v |
||||
构造 PHP 动态参数列表 |
||||
| |
||||
v |
||||
查找函数或方法 |
||||
| |
||||
v |
||||
调用 PHP VM 动态路径 |
||||
| |
||||
v |
||||
返回 php::Var 动态值 |
||||
``` |
||||
|
||||
#### 5.9.3 静态数据流入动态态 |
||||
|
||||
例如强类型容器赋值给普通 PHP 变量时,自动转换为 PHP Array: |
||||
|
||||
```php |
||||
$arr = $vector; |
||||
``` |
||||
|
||||
生成: |
||||
|
||||
```cpp |
||||
arr = php::toArray(vector); |
||||
``` |
||||
|
||||
#### 5.9.4 动态对象流入静态态 |
||||
|
||||
当从动态数组或函数返回值取出对象,而后续需要静态方法调用时,可通过编译期类型声明函数或类型转换函数告知编译器对象类名,从而进入静态对象态。 |
||||
|
||||
### 5.10 符号缓存机制 |
||||
|
||||
为减少动态态运行时字符串查找开销,本发明为符号建立整数编号和缓存数组: |
||||
|
||||
```cpp |
||||
zend_class_entry *class_map[N]; |
||||
zend_function *func_map[M]; |
||||
uint32_t property_map[K]; |
||||
``` |
||||
|
||||
首次查找时根据字符串名称取得 Zend 结构指针并缓存;后续调用通过整数 ID 快速访问。 |
||||
|
||||
示例: |
||||
|
||||
```cpp |
||||
zend_function *get_func(int id, const php::Str &name) { |
||||
if (func_map[id] == nullptr) { |
||||
func_map[id] = php::getFunction(name); |
||||
} |
||||
return func_map[id]; |
||||
} |
||||
``` |
||||
|
||||
该机制使动态态仍然比纯解释路径更高效。 |
||||
|
||||
### 5.11 双运行形态 |
||||
|
||||
本发明支持两种运行形态: |
||||
|
||||
1. **扩展形态**:编译结果是 PHP 扩展,可加载到 PHP-FPM 或 CLI 中,由 PHP VM 调用。 |
||||
2. **二进制形态**:编译结果是可执行程序,由 `main()` 函数作为入口,可直接运行。 |
||||
|
||||
这两种形态共享同一套混合态编译模型。 |
||||
|
||||
## 6. 关键点和欲保护点 |
||||
|
||||
1. 提出一种混合态编程语言模型,使同一动态语言程序中同时存在静态态和动态态。 |
||||
2. 在编译器中按函数、方法、变量、表达式和调用点自动判定静态态或动态态。 |
||||
3. 对可确定目标生成 C++ 静态直连代码,对不可确定目标自动回退到 PHP 动态调用代码。 |
||||
4. 使用 ArgInfo 作为静态态和动态态共享的参数语义模型。 |
||||
5. 生成 Zend 包装函数,使动态运行时可以调用 AOT 生成的 Native 函数。 |
||||
6. 在 AOT 静态代码中构造动态参数列表,使静态代码可以调用 PHP 动态函数、动态方法或回调。 |
||||
7. 使用符号缓存机制减少动态态运行时的函数、类、方法、属性字符串查找开销。 |
||||
8. 支持扩展形态和二进制形态两种运行产物,均基于同一混合态语言模型。 |
||||
9. 在静态态中支持原生类型和 C++ 模版容器,在动态态中保留 zval、php::Var、PHP Array 和 PHP 对象语义。 |
||||
|
||||
## 7. 与现有技术相比的优点 |
||||
|
||||
与传统静态编译语言相比,本发明保留了动态语言的动态调用、动态类型、动态对象和回调能力,不要求程序完全静态化。 |
||||
|
||||
与传统动态解释语言相比,本发明可在编译期确定的区域生成 C++ 直接调用、原生类型和强类型容器,显著减少运行时查找和动态类型开销。 |
||||
|
||||
与 JIT 相比,本发明在部署前生成稳定的编译产物,不依赖运行时热点采样和类型反馈,适合需要稳定部署、保护源码和提升性能的生产环境。 |
||||
|
||||
与手写扩展相比,本发明由编译器自动生成包装函数、参数转换、符号缓存和动态回退路径,降低开发者在 PHP 与 C++ 之间手动桥接的成本。 |
||||
|
||||
## 8. 可选实施方式 |
||||
|
||||
本发明不限于 PHP,也可用于 Python、JavaScript、Ruby、Lua 等动态语言。目标静态语言不限于 C++,也可为 Rust、Go、C 或 LLVM 中间表示。 |
||||
|
||||
混合态判定粒度可以是函数级、基本块级、语句级或表达式级。符号缓存也可使用哈希表、数组、句柄表或运行时内联缓存实现。 |
||||
|
||||
## 9. 保密说明 |
||||
|
||||
本文档涉及 Swoole-Compiler 的整体编译模型、静态直连与动态回退策略、ArgInfo 边界桥接机制和符号缓存方案。正式申请前建议作为内部技术资料管理。 |
||||
@ -0,0 +1 @@ |
||||
技术交底书该技术应用产品:1、详细介绍技术背景,并描述已有的与本发明最相近似的实现方案(包括两部分:背景技术及现有技术方案[大的技术背景和小的技术背景],应详细介绍,以不需再去看文献即可领会该技术内容为准,如果现有技术出自专利、期刊、书籍,则提供出处)2、现有技术的缺点是什么?针对这些缺点,说明本发明的目的。(客观评价,现有技术的缺点是针对于本发明的优点来说的,本发明不能解决的缺点不必写;基于本发明能解决的问题写出发明的目的)3、本发明技术方案的详细阐述,应该结合示意图进行说明(越详细越好,至少要提供2页;发明中每一功能的实现都要有相应的技术实现方案;所有英文缩写都应有中文注释;所有附图都应该有详细的文字描述,以别人不看附图即可明白技术方案为准;同时附图中的关键词或方框图中的注释都尽量用中文;方法专利都应该提供流程图,并提供相关的系统装置图;附图中各相关部件都要提供名称)。4、本发明的关键点和欲保护点是什么?(发明内容部分提供的是为完成一定功能的完整技术方案,在本部分是提炼出技术方案的关键创新点,列出1、2、3…,以提醒代理人注意,便于代理人撰写权利要求书5、与第1部分最好的现有技术相比,本发明有何优点(结合发明内容简单介绍,一两个自然段即可)注意:1.代理人并不是技术专家,交底书要使代理人能看懂,尤其是背景技术和详细技术方案,一定要写的全面、清楚。2.英文缩写有中文译文,避免使用英文单词,最好在术语解释部分给出。3.全文对同一事物的叫法应统一,避免出现一种东西多种叫法。4.认为需要保密的地方可在交底书中注明,对代理人不必保密。5.专利法规定:1)专利必须是一个技术方案,应该阐述发明目的是通过什么技术方案来实现的,不能只有原理,也 不能只做功能介绍; 2)专利必须充分公开,以本领域技术人员不需付出创造性劳动即可实现为准。 |
||||
Loading…
Reference in new issue