refactor(tpv): 删除 FuncEntry.TypeStr 旧路径,函数类型文本改由 Spec 派生

- 删 FuncEntry.TypeStr 字段、_build_func_type_str 生产者、_check_func_spec_text 闸门
- update_global_func_typestr 改名 update_global_func_spec,仅填 Spec(去 pool 参数)
- ClassGenVTable vtable 合并 func_valid 分支,统一 SpecToLLVMText 派生
- 同步 FuncGenDef/ClassGenVTable/GenApi/VpiReader 调用点
This commit is contained in:
TermiNexus committed 2026-09-11 21:33:58 +08:00
1 parent a173ba0296
commit 0a108e6289
7 files changed
+44 -185

No files matched your search

+8 -8
View File
@@ -2349,10 +2349,10 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr,
if GenApi.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs,
fd_defaults, fd_default_count, param_count, None, src_sha1) == 0:
trans._func_count = cur_count + 1
# 补全全局函数表 TypeStr(参数已全部添加,对齐 FuncGenDef L211 行为):
# vpi 注入路径若不补全,跨模块 vtable/调用解析 find_func_entry_global()
# 时 TypeStr 为空 → "vtable 方法找不到函数实现"(依赖模块晚于本模块编译时必现)
GenApi.update_global_func_typestr(pool, fd.name, func)
# 补全全局函数表 Spec(参数已全部添加,对齐 FuncGenDef 行为):
# vpi 注入路径若不补全,跨模块 vtable 生成 find_func_entry_global()
# 时 Spec 为空 → "vtable 方法找不到函数类型"(依赖模块晚于本模块编译时必现)
GenApi.update_global_func_spec(fd.name, func)
# ============================================================
@@ -2541,11 +2541,11 @@ def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr,
if GenApi.add_func_to_table(funcs_ptr, cur_count, lookup_name, func, max_funcs,
md_defaults, md_default_count, param_count_no_self, None, src_sha1) == 0:
trans._func_count = cur_count + 1
# 补全全局函数表 TypeStr(参数已全部添加,对齐 ClassGenVTable L832 行为):
# vpi 注入的方法声明若不补全 TypeStr,跨模块继承 vtable 生成时
# find_func_entry_global().TypeStr 为空 → "vtable 方法找不到函数实现"
# 补全全局函数表 Spec(参数已全部添加,对齐 ClassGenVTable 行为):
# vpi 注入的方法声明若不补全 Spec,跨模块继承 vtable 生成时
# find_func_entry_global().Spec 为空 → "vtable 方法找不到函数类型"
# (astaux.vp 先于 ast.base.vp 编译时必现:AST.accept 仅有 vpi 注入条目)
GenApi.update_global_func_typestr(pool, lookup_name, func)
GenApi.update_global_func_spec(lookup_name, func)
# ============================================================
+12 -102
View File
@@ -1003,7 +1003,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
defaults: ast.Arguments.defaults 列表节点指针,None=无默认值
default_count: 默认值数量(len(defaults))
param_count: 形参数量(不含 self,len(args.args))
pool: 内存池(用于生成 TypeStr;None 时 TypeStr 为空,vtable 回退读 Func 对象)
pool: 内存池(保留兼容参数;Spec 由 arena/PermPool 分配)
"""
if name is None or func is None or funcs is None:
return 1
@@ -1017,7 +1017,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
entry.Defaults = defaults
entry.DefaultCount = default_count
entry.ParamCount = param_count
# [S3 条目双写] Spec 在形参 add_param 完成后由 update_global_func_typestr 填
# [S3 条目双写] Spec 在形参 add_param 完成后由 update_global_func_spec 填
entry.Spec = None
# 同时注册到全局函数表(供跨模块 vtable 初始化查找)
self._register_global_func(name, func, pool)
@@ -1040,67 +1040,11 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
return 1
def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr,
func: llvmlite.Function | t.CPtr) -> str:
"""生成函数类型文本(stdlib 分配)"""
if func is None:
return None
# 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲
ty_buf: str = pool.alloc(1024)
if ty_buf is None:
return None
ty_buf[0] = '\0'
# 返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func)
ret_part: str = pool.alloc(512)
if ret_part is not None and ret_ty is not None:
ret_part[0] = '\0'
llvmlite.TypePrint(ret_part, 512, ret_ty, pool)
self._asm_append_cstr(ty_buf, 1024, ret_part)
self._asm_append_cstr(ty_buf, 1024, " (")
# 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲)
cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
first: int = 1
param_part: str = pool.alloc(512)
while cur is not None:
if first == 0:
self._asm_append_cstr(ty_buf, 1024, ", ")
if param_part is not None:
param_part[0] = '\0'
param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur)
if param_ty is not None:
llvmlite.TypePrint(param_part, 512, param_ty, pool)
self._asm_append_cstr(ty_buf, 1024, param_part)
cur = llvmlite.param_get_next(cur)
first = 0
# 变参函数追加 ...(对齐 llvmlite IR 打印规则,见 includes/llvmlite/__function.vp
# L1145-1150:有参数时 ", ...",无参数时 "...")。此前遗漏 → 跨模块继承方法的
# vtable 回退路径(ClassGenVTable 对继承方法强制 func_valid=0,只能用本文本)
# 生成的函数类型缺 ...,与真实签名不符(本函数为 TypeStr 的唯一生产者)。
if func.IsVarArg == 1:
if first != 0:
self._asm_append_cstr(ty_buf, 1024, "...")
else:
self._asm_append_cstr(ty_buf, 1024, ", ...")
self._asm_append_cstr(ty_buf, 1024, ")")
# 深拷贝到 stdlib 区(TypeStr 跨文件永久存活)
ts_len: sizet = string.strlen(ty_buf)
ts_copy: str = CompilerFactory.factory.PermPool.alloc(ts_len + 1)
if ts_copy is None:
return None
string.strcpy(ts_copy, ty_buf)
return ts_copy
def _register_global_func(self, name: str, func: llvmlite.Function | t.CPtr,
pool: memhub.MemBuddy | t.CPtr = None) -> int:
"""注册函数到全局表(已存在则跳过),返回 0 成功
直接操作全局表,不调用 add_func_to_table,避免递归。
pool 用于生成 TypeStr(None 时 TypeStr 为空)。
"""
if name is None or func is None:
return 1
@@ -1124,34 +1068,28 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
string.strcpy(name_copy, name)
entry.Name = name_copy
entry.Func = func
# [S3 条目双写] Spec 待 update_global_func_typestr 填(形参未 add 完)
# [S3 条目双写] Spec 待 update_global_func_spec 填(形参未 add 完)
entry.Spec = None
# TypeStr 不在此生成:函数参数在 add_func_to_table 之后才添加,
# 需由调用方在参数添加完成后调用 update_global_func_typestr 补全。
# Spec 不在此生成:函数参数在 add_func_to_table 之后才添加,
# 需由调用方在参数添加完成后调用 update_global_func_spec 补全。
self.GlobalFuncCount += 1
return 0
def update_global_func_typestr(self, pool: memhub.MemBuddy | t.CPtr,
name: str,
func: llvmlite.Function | t.CPtr) -> int:
"""更新全局函数表的 TypeStr(在函数参数全部添加完成后调用)
def update_global_func_spec(self, name: str,
func: llvmlite.Function | t.CPtr) -> int:
"""更新全局函数表的 Spec(在函数参数全部添加完成后调用)
调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。
生成 ret_ty (param1_ty, ...) 类型文本(stdlib 深拷贝),
供 vtable 生成在 func 被 1b reset 后使用。
用 NewTypeFunc 构造整签名 Spec(PermPool 驻留,跨 1b reset 安全),
供 vtable 生成在 func 被 1b reset 后经 SpecToLLVMText 派生类型文本。
"""
if name is None or func is None:
return 1
entry: GenTypes.FuncEntry | t.CPtr = self.find_func_entry_global(name)
if entry is None:
return 1
entry.TypeStr = self._build_func_type_str(pool, func)
# [S3 条目双写] 整签名 Spec(与 TypeStr 同源同表;此处形参已全部 add_param)
entry.Spec = self._build_func_spec(func)
# [S3 格式化闸门] Spec 侧 LLVM 文本与旧生产者逐字节比对 —— 后续
# 「删掉 _build_func_type_str、TypeStr 改由 Spec 派生」的前置实证。
self._check_func_spec_text(pool, entry)
return 0
@@ -1159,7 +1097,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
# _build_func_spec - 由函数对象构造整签名 TypeSpec(S3 条目双写)
#
# Kind=TS_FUNC:Ret + 形参 Spec 数组 + ParamCount + IsVarArg。必须在形参
# 全部 add_param 完成后调用(同 _build_func_type_str 的时机)。
# 全部 add_param 完成后调用。
# 参数沿 `llvmlite.function_get_param_head` 的 Param 链表**两遍遍历**(先计数
# 再填充)——llvmlite 无按下标取参,且无法预知长度以一次分配。
# 注意与 `TSpec.SpecFromLLVMType` 的 Func 分支的区别:后者只能看到
@@ -1207,34 +1145,6 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
return TSpec.NewTypeFunc(arena, ret_s, params_arr, cnt, func.IsVarArg)
# ============================================================
# _check_func_spec_text - 格式化闸门:Spec 侧 LLVM 文本 vs 旧生产者
#
# 用 `TSpec.SpecToLLVMText(entry.Spec)` 与 `entry.TypeStr`(`_build_func_type_str`
# 经 llvmlite.TypePrint 产出)**逐字节**比对,不一致即 fatal —— 这是"删掉旧生产者、
# TypeStr 改由 Spec 派生"的前置实证(Debugger/_Type.md:暴露而非静默)。
# 跳过条件(「不适用」≠「不一致」):Spec 为 None、TypeStr 为 None、
# 或 SpecToLLVMText 返回 1(如匿名结构体 Spec 未保留字段列表,无法还原 "{...}")。
# ============================================================
def _check_func_spec_text(self, pool: memhub.MemBuddy | t.CPtr,
entry: GenTypes.FuncEntry | t.CPtr) -> None:
"""Spec 侧 LLVM 文本与旧 TypeStr 一致性比对(闸门)"""
if pool is None or entry is None or entry.Spec is None:
return
if entry.TypeStr is None:
return
spec_txt: str = pool.alloc(1024)
if spec_txt is None:
return
spec_txt[0] = '\0'
if TSpec.SpecToLLVMText(entry.Spec, spec_txt, 1024) != 0:
return
if string.strcmp(entry.TypeStr, spec_txt) == 0:
return
msg: str = f"[S3 格式化闸门] 函数签名文本不一致 旧={entry.TypeStr} 新={spec_txt}"
self.Gen.TypeGenErr.fatal_error(None, msg, "TypeError")
def find_func_global(self, name: str) -> llvmlite.Function | t.CPtr:
"""在全局函数表中按名称查找,返回 Function 指针或 None"""
if name is None or self.GlobalFuncs is None:
@@ -1243,7 +1153,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
def find_func_entry_global(self, name: str) -> GenTypes.FuncEntry | t.CPtr:
"""在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None"""
"""在全局函数表中按名称查找,返回完整 FuncEntry(含 Spec)或 None"""
if name is None or self.GlobalFuncs is None:
return None
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
+10 -56
View File
@@ -355,67 +355,21 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
# 继承方法: 用父类模块 SHA1 做 mangling
parent_sha1: str = (str | t.CPtr)(t.CVoid(parent_sha1_addr, t.CPtr))
mangled_name: str = self.Gen.FuncGenBase._mangle_name_with_sha1(parent_sha1, full_name)
# 从全局函数表查找(跨模块函数不在当前模块表中)
func: llvmlite.Function | t.CPtr = self.Gen.CallGenLeafKit.find_func_global(full_name)
else:
# 当前类方法: 用当前模块 SHA1
mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name)
func: llvmlite.Function | t.CPtr = self.Gen.CallGenLeafKit.find_func_in_table(
trans._funcs, trans._func_count, full_name)
# 当前模块表找不到时,回退到全局表
if func is None:
func = self.Gen.CallGenLeafKit.find_func_global(full_name)
# func 可能已被 1b reset_to(mark1) 回收(跨模块继承方法在定义文件翻译后被 reset)。
# 悬空指针非 NULL 但内容已被复用,解引用会沿垃圾 Next 链指针追逐导致无限分配。
# 因此 func 非 NULL 时也须用 _is_valid_ptr 校验,失败回退到全局表 TypeStr。
func_valid: int = 0
if func is not None:
if trans.Pool is not None:
# 继承方法(parent_sha1_addr != 0):func 来自其他模块,该模块 1b 翻译
# 后已被 reset_to(mark1) 回收,_is_valid_ptr 存在假阳性(块头复用后仍
# 看似有效),直接判定无效走 TypeStr 回退,避免解引用悬空 func 崩溃。
if parent_sha1_addr != 0:
func_valid = 0
elif trans.Pool._is_valid_ptr(func) != 0:
func_valid = 1
if func_valid == 0:
# 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。
ge: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_entry_global(full_name)
if ge is not None and ge.TypeStr is not None:
self._vtable_strcat(init_buf, 16384, "i8* bitcast (")
self._vtable_strcat(init_buf, 16384, ge.TypeStr)
self._vtable_strcat(init_buf, 16384, "* @")
if self._vtable_name_needs_quote(mangled_name) != 0:
self._vtable_strcat(init_buf, 16384, "\"")
self._vtable_strcat(init_buf, 16384, mangled_name)
self._vtable_strcat(init_buf, 16384, "\"")
else:
self._vtable_strcat(init_buf, 16384, mangled_name)
self._vtable_strcat(init_buf, 16384, " to i8*)")
continue
# fail-fast:func 无效且全局表 TypeStr 回退也失败,
# 不再写 "i8* null" 静默掩盖缺失实现。
self.Gen.TypeGenErr.fatal_error(
cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError")
continue
# 构造函数类型字符串(S3 切读:优先 SpecToLLVMText 派生,回退全局表 TypeStr;
# 替代 _format_func_type_str 那份 512 缓冲 + >100 参截断的 TypePrint 重复实现)
# 统一从全局表 entry.Spec 用 SpecToLLVMText 派生函数类型文本。
# 全局表 entry.Spec 在方法 add_param 完成后由 update_global_func_spec 填
# (PermPool 驻留,跨 1b reset 安全),故不再解引用 func(func 可能已被
# reset_to(mark1) 回收悬空)。
ge: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_entry_global(full_name)
func_ty_buf: str = pool.alloc(1024)
if func_ty_buf is None:
self._vtable_strcat(init_buf, 16384, "i8* null")
continue
func_ty_buf[0] = '\0'
ty_ok: int = 0
spec_entry2: GenTypes.FuncEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_entry_global(full_name)
if spec_entry2 is not None and spec_entry2.Spec is not None:
if TSpec.SpecToLLVMText(spec_entry2.Spec, func_ty_buf, 1024) == 0:
ty_ok = 1
if ty_ok == 0 and spec_entry2 is not None and spec_entry2.TypeStr is not None:
string.strcpy(func_ty_buf, spec_entry2.TypeStr)
ty_ok = 1
if ty_ok == 0:
if ge is None or ge.Spec is None or TSpec.SpecToLLVMText(ge.Spec, func_ty_buf, 1024) != 0:
self.Gen.TypeGenErr.fatal_error(
cd, f"vtable 方法 '{full_name}' 找不到函数类型", "InternalCompilerError")
continue
@@ -827,8 +781,8 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
if i1_ptr_ty_si is not None:
llvmlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__")
# 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用)
self.Gen.CallGenLeafKit.update_global_func_typestr(pool, full_name, func)
# 参数添加完成,补全全局函数表的 Spec(供 vtable 在 func 被 reset 后派生类型文本)
self.Gen.CallGenLeafKit.update_global_func_spec(full_name, func)
# 创建 entry 块
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
@@ -1171,8 +1125,8 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
# 添加 self 参数
llvmlite.add_param(pool, func, self_ptr_ty, "%self")
# 参数添加完成,补全全局函数表的 TypeStr
rc_ut: int = self.Gen.CallGenLeafKit.update_global_func_typestr(pool, full_name, func)
# 参数添加完成,补全全局函数表的 Spec
rc_ut: int = self.Gen.CallGenLeafKit.update_global_func_spec(full_name, func)
# 创建 entry 块 + builder
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
+6 -6
View File
@@ -278,8 +278,8 @@ class FuncGenDef(CallGenBase.CallGenBase):
if ags.vararg is not None:
func.IsVarArg = 1
# 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用)
self.Gen.CallGenLeafKit.update_global_func_typestr(trans.Pool, fd.name, func)
# 参数添加完成,补全全局函数表的 Spec(供 vtable 在 func 被 reset 后派生类型文本)
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
# 泛型函数上下文用完即清(防泄漏到后续函数的注解解析)
if tp_names_fd is not None:
@@ -546,8 +546,8 @@ class FuncGenDef(CallGenBase.CallGenBase):
if func_section_e is not None:
llvmlite.function_set_attr_group(func, func_section_e)
# 参数添加完成,补全全局函数表的 TypeStr
self.Gen.CallGenLeafKit.update_global_func_typestr(pool, fd.name, func)
# 参数添加完成,补全全局函数表的 Spec
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
return 0
@@ -662,8 +662,8 @@ class FuncGenDef(CallGenBase.CallGenBase):
llvmlite.add_param(pool, func, i8_ptr_ptr_ty_eh, "%__eh_msg_out__")
llvmlite.add_param(pool, func, i32_ptr_ty_eh, "%__eh_code_out__")
# 参数添加完成,补全全局函数表的 TypeStr
self.Gen.CallGenLeafKit.update_global_func_typestr(trans.Pool, fd.name, func)
# 参数添加完成,补全全局函数表的 Spec
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
# 创建 entry 块
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
+5 -6
View File
@@ -577,11 +577,10 @@ def clear_scope_names(trans: HT.Translator | t.CPtr):
_g_gen.TranslatorGen.clear_scope_names(trans)
# ---------------- update_global_func_typestr(委托 CallGenLeafKit.update_global_func_typestr) ----------------
def update_global_func_typestr(pool: memhub.MemBuddy | t.CPtr,
name: str,
func: llvmlite.Function | t.CPtr) -> int:
"""委托到 gen.CallGenLeafKit.update_global_func_typestr(原 ExprCallTable 壳)"""
# ---------------- update_global_func_spec(委托 CallGenLeafKit.update_global_func_spec) ----------------
def update_global_func_spec(name: str,
func: llvmlite.Function | t.CPtr) -> int:
"""委托到 gen.CallGenLeafKit.update_global_func_spec(原 ExprCallTable 壳)"""
if _g_gen is not None:
return _g_gen.CallGenLeafKit.update_global_func_typestr(pool, name, func)
return _g_gen.CallGenLeafKit.update_global_func_spec(name, func)
return 0
+1 -5
View File
@@ -182,12 +182,8 @@ class FuncEntry:
Defaults: t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值
DefaultCount: int # 默认值数量
ParamCount: int # 形参数量(不含 self)
# TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全)
# 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后,
# vtable 生成 find_func_global 读类型改用此文本,避免悬空。
TypeStr: str
# TypeSpec(S3 条目双写):Kind=TS_FUNC 的**整签名**(Ret/Params/ParamCount/
# IsVarArg 都在其内),由 update_global_func_typestr 在形参 add_param 完成后
# IsVarArg 都在其内),由 update_global_func_spec 在形参 add_param 完成后
# 用 NewTypeFunc 构造(含 func.IsVarArg)。PermPool 驻留 ⇒ 跨 1b reset 安全。
# 说明:设计 D4 原写 RetSpec+ParamSpecs 两字段,此处合并为单个 Spec —— 单字段
# 即可完整表达签名,且与 VarEntry/FieldEntry 的 Spec 命名一致,避免参数数组重复。
+2 -2
View File
@@ -865,8 +865,8 @@ def SpecTypePtrLevel(ty: llvmlite.LLVMType | t.CPtr) -> int:
# ============================================================
# SpecToLLVMText - TypeSpec → LLVM IR 类型文本(**逐字节对齐 llvmlite.TypePrint**)
#
# 用途:让 `FuncEntry.TypeStr` 改由 Spec 派生(随后即可删掉字符串生产者),
# 推进去字符串化(Debugger/_Type.md D14 起)。当前阶段先用作**比对闸门**。
# 用途:作为 FuncEntry.Spec 的 LLVM 文本派生源(旧 FuncEntry.TypeStr 字符串生产者
# 已在 S4 删除),推进去字符串化(Debugger/_Type.md D14 起)。
#
# 对齐依据:`includes/llvmlite/__types.vp:395-511` 的 `_TypePrintDepth`,逐分支照搬:
# Int(bits) → "iN"(**无符号也是 iN** —— LLVM 文本层不分符号)