fix(callgencall): 根治——跨模块 declare 创建后按形参类型 coerce 实参
found_func=None 路径(跨模块调用)创建 declare 后未 coerce 实参,字面量 0=i32 传 i64 形参(t.CSizeT)未提升 → llc 按 i32 布局栈参(movl 4 字节写)→ i64 形参高 4 字节残留垃圾 → callee 读 can=[垃圾][count] 崩溃(SlotsBugTest/StringIterTest 根因,反汇编 movl 实锤)。 修复:与 found_func 路径(L588-611)同逻辑,_ensure_method_declare 后用 self.find_func_in_module 取 declare 形参类型,coerce_to_type 提升/截断整数实参(i32 0 → sext i64 0),使 IR call 实参与 declare 一致。覆盖所有跨模块调用点。
This commit is contained in:
1 parent
a9d71714b3
commit
decf74b946
1 file changed
+293
-63
+293
-63
@@ -79,15 +79,28 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
vtable_base = self_ptr
|
||||
|
||||
# 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
|
||||
# 必须用 vtable_base(对象头)的类型而非 self_ptr:多继承 this 调整后
|
||||
# self_ptr 已 bitcast 成父类指针(如 ColorM*),用其解析会得到父类
|
||||
# vtable 布局(单槽 {i8*})→ method_index/method_count 按父类算,
|
||||
# GEP 槽位错位读到别的函数(MultiInheritTest color_code 虚调用读到
|
||||
# area FAILED 根因)。vtable_base 是接收者静态类型指针(vtable 所在
|
||||
# 位置),其 VTableMethods 才是最终对象实际存储的完整 vtable 布局。
|
||||
vc_entry: GenTypes.StructEntry | t.CPtr = None
|
||||
struct_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if self_ptr.Ty is not None:
|
||||
vc_entry = self.Gen.StructGen.get_struct_type_from_value(self_ptr)
|
||||
if vtable_base is not None and vtable_base.Ty is not None:
|
||||
vc_entry = self.Gen.StructGen.get_struct_type_from_value(vtable_base)
|
||||
if vc_entry is not None:
|
||||
# vc_entry 是 struct_ty(LLVMType),需要找 StructEntry
|
||||
vc_entry = self.Gen.StructGen.find_struct_by_type(vc_entry)
|
||||
if vc_entry is not None:
|
||||
struct_ty = vc_entry.Ty
|
||||
if struct_ty is None and self_ptr is not None and self_ptr.Ty is not None:
|
||||
# fallback:vtable_base 无类型信息时退回 self_ptr(未调整场景两者一致)
|
||||
vc_entry = self.Gen.StructGen.get_struct_type_from_value(self_ptr)
|
||||
if vc_entry is not None:
|
||||
vc_entry = self.Gen.StructGen.find_struct_by_type(vc_entry)
|
||||
if vc_entry is not None:
|
||||
struct_ty = vc_entry.Ty
|
||||
if struct_ty is None:
|
||||
struct_ty = self.Gen.StructGen.get_struct_type(class_name)
|
||||
if struct_ty is None:
|
||||
@@ -420,6 +433,48 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
mdf_default_count = mdf_gd.DefaultCount
|
||||
mdf_param_count = mdf_gd.ParamCount
|
||||
|
||||
# 跨模块 stub 未注入兜底(同 _translate_method_call):found_func 为
|
||||
# None 且函数表无 ParamCount 时,用 vpi 文本缓存补全参数数,默认
|
||||
# 参数填充(含零值兜底)随即生效,declare/call 与 define 对齐。
|
||||
vpi_pa: str = None
|
||||
if mdf_param_count == 0 and found_func is None:
|
||||
vpi_sha1_p: str = None
|
||||
if cmop_entry is not None and cmop_entry.ModuleSha1 is not None:
|
||||
vpi_sha1_p = cmop_entry.ModuleSha1
|
||||
else:
|
||||
vpi_sha1_p = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if vpi_sha1_p is not None:
|
||||
vpi_pa = self.Gen.CallGenBase._vpi_method_param_annot(
|
||||
pool, vpi_sha1_p, class_name, method_name)
|
||||
if vpi_pa is not None and vpi_pa[0] != '\0':
|
||||
vpi_pc2: int = 1
|
||||
vi2: t.CSizeT = 0
|
||||
while vpi_pa[vi2] != '\0':
|
||||
if vpi_pa[vi2] == '@':
|
||||
vpi_pc2 += 1
|
||||
vi2 += 1
|
||||
mdf_param_count = vpi_pc2 - 1 # 非 self 参数数
|
||||
|
||||
# [修复 2026-08-25] found_func 参数数回退(同 _translate_method_call):
|
||||
# 函数表/默认表无 ParamCount 但 found_func(declare)已找到时用其参数数
|
||||
# 作补全基准,否则省略默认参数(如 translate_value 的 target_ty=None)
|
||||
# 的调用补全不触发 → call 实参 < define 形参 → ABI 错位读栈残留垃圾。
|
||||
# 排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__):含 raise 函数
|
||||
# 定义尾部注入 2 个 EH 形参,计入会让 _emit_eh_guarded_call 追加真实
|
||||
# EH 实参前先补 zeroinitializer 占位 → 双重注入 call 实参多 2(TestFBProject
|
||||
# raise_disk() 崩溃根因,与 CallGenMixin 零值兜底同源)。
|
||||
if mdf_param_count == 0 and found_func is not None:
|
||||
ppcnt_f2: int = 0
|
||||
ppn_f2: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
while ppn_f2 is not None:
|
||||
fp_nm_f2: str = llvmlite.param_get_name(ppn_f2)
|
||||
if fp_nm_f2 is None or (string.strcmp(fp_nm_f2, "%__eh_msg_out__") != 0
|
||||
and string.strcmp(fp_nm_f2, "%__eh_code_out__") != 0):
|
||||
ppcnt_f2 += 1
|
||||
ppn_f2 = llvmlite.param_get_next(ppn_f2)
|
||||
if ppcnt_f2 > 1:
|
||||
mdf_param_count = ppcnt_f2 - 1 # 非 self 非 EH 参数数
|
||||
|
||||
# 计算需要填充的参数(不含 self)
|
||||
# extra_count = 已提供的非 self 参数数量
|
||||
# mdf_param_count = 函数定义的非 self 参数数量
|
||||
@@ -470,6 +525,40 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
llvmlite.value_set_next(tail, zero_val)
|
||||
tail = zero_val
|
||||
total_count += 1
|
||||
elif vpi_pa is not None:
|
||||
# found_func 为 None(stub 未注入):用 vpi 参数注解解析
|
||||
# 缺失参数类型(段索引 mdf_pi+1,跳过首参 self 空段),
|
||||
# 值取类型零值(默认参数值恰为零值;查不到 ≠ 无默认值)。
|
||||
seg_idx_v: int = mdf_pi + 1
|
||||
seg_no_v: int = 0
|
||||
seg_cur_v: t.CSizeT = 0
|
||||
while seg_no_v < seg_idx_v and vpi_pa[seg_cur_v] != '\0':
|
||||
if vpi_pa[seg_cur_v] == '@':
|
||||
seg_no_v += 1
|
||||
seg_cur_v += 1
|
||||
seg_start_v: t.CSizeT = seg_cur_v
|
||||
seg_len_v: t.CSizeT = 0
|
||||
while vpi_pa[seg_start_v + seg_len_v] != '\0' \
|
||||
and vpi_pa[seg_start_v + seg_len_v] != '@':
|
||||
seg_len_v += 1
|
||||
if seg_no_v == seg_idx_v:
|
||||
pty_v: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if seg_len_v > 0:
|
||||
seg_buf_v: bytes = stdlib.malloc(seg_len_v + 1)
|
||||
if seg_buf_v is not None:
|
||||
string.strncpy(seg_buf_v, vpi_pa + seg_start_v, seg_len_v)
|
||||
seg_buf_v[seg_len_v] = '\0'
|
||||
rty_v: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenBase._vpi_resolve_param_annot_ty(
|
||||
pool, seg_buf_v)
|
||||
if rty_v is not None:
|
||||
pty_v = rty_v
|
||||
stdlib.free(seg_buf_v)
|
||||
zero_val_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, pty_v)
|
||||
if zero_val_v is not None:
|
||||
llvmlite.value_set_next(zero_val_v, None)
|
||||
llvmlite.value_set_next(tail, zero_val_v)
|
||||
tail = zero_val_v
|
||||
total_count += 1
|
||||
mdf_pi += 1
|
||||
elif found_func is not None:
|
||||
# 无默认参数信息但有 found_func:用零值兜底填充缺失参数
|
||||
@@ -558,6 +647,36 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
# 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value
|
||||
if found_func is None:
|
||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
|
||||
# [根治] declare 创建后按形参类型 coerce 实参(与上方 found_func 路径
|
||||
# 的 L588-611 同逻辑,缺失导致字面量 0=i32 传 i64 形参(t.CSizeT)未提升:
|
||||
# llc 按 i32 布局栈参(movl 4 字节写)→ i64 形参高 4 字节残留垃圾 →
|
||||
# callee 读 can=[垃圾][count] 崩溃,SlotsBugTest/StringIterTest 根因,
|
||||
# 反汇编 movl 实锤)。coerce 使 IR call 实参与 declare 形参类型一致。
|
||||
dc_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
|
||||
if dc_func is not None and head is not None:
|
||||
dc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(dc_func)
|
||||
dc_node: llvmlite.Value | t.CPtr = head
|
||||
dc_new_head: llvmlite.Value | t.CPtr = head
|
||||
dc_prev: llvmlite.Value | t.CPtr = None
|
||||
while dc_node is not None:
|
||||
dc_next: llvmlite.Value | t.CPtr = dc_node.Next
|
||||
dc_cur: llvmlite.Value | t.CPtr = dc_node
|
||||
if dc_param is not None:
|
||||
dc_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(dc_param)
|
||||
if dc_pty is not None:
|
||||
dc_c: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, dc_node, dc_pty, None)
|
||||
if dc_c is not None:
|
||||
dc_cur = dc_c
|
||||
dc_param = llvmlite.param_get_next(dc_param)
|
||||
dc_cur.Next = None
|
||||
if dc_prev is None:
|
||||
dc_new_head = dc_cur
|
||||
else:
|
||||
dc_prev.Next = dc_cur
|
||||
dc_prev = dc_cur
|
||||
dc_node = dc_next
|
||||
head = dc_new_head
|
||||
|
||||
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
|
||||
# ============================================================
|
||||
@@ -648,45 +767,64 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
mixin_anc_name: str = None
|
||||
mixin_anc_sha1: str = None
|
||||
if found_func is None:
|
||||
sc_i: int = 0
|
||||
sc_n: int = self.Gen.StructGen.get_struct_count()
|
||||
while sc_i < sc_n and found_func is None and mixin_hit == 0:
|
||||
cand_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen._get_struct_entry(sc_i)
|
||||
if cand_entry is not None and cand_entry.Name is not None:
|
||||
cand_name: str = cand_entry.Name
|
||||
if string.strcmp(cand_name, class_name) != 0:
|
||||
# 泛型特化类名含 '['(list[...]/dict[...]):跳过,
|
||||
# 不是兄弟 Mixin 候选(见上方注释)
|
||||
if string.strchr(cand_name, '[') is not None:
|
||||
sc_i += 1
|
||||
continue
|
||||
cand_lookup: str = pool.alloc(128)
|
||||
if cand_lookup is not None:
|
||||
viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name)
|
||||
cand_func: llvmlite.Function | t.CPtr = self.find_func_in_module(
|
||||
mod, cand_lookup)
|
||||
if cand_func is not None:
|
||||
found_func = cand_func
|
||||
mc_anc = cand_name
|
||||
else:
|
||||
# 跨模块 Mixin(定义类在另一文件,本地 IR 无 define):
|
||||
# 用候选类模块 sha1 查 text.ll 返回类型,命中即锁定定义类,
|
||||
# 后续 ret_anc_* 据此构造 {sha1}.{class}.{method} 调用名。
|
||||
# 否则 ret_anc_sha1 停在调用类自身 sha1,_dep_text_ll_exists
|
||||
# 查自身 text.ll(Phase A 翻译中未生成)→ 永久 pending 死锁
|
||||
# (ClassGenVTable._mangle_name → 7871cc1aabebfc33 根因)。
|
||||
if mixin_hit == 0:
|
||||
cand_sha1_cx: str = self.Gen.StructGen.get_struct_sha1(cand_name)
|
||||
if cand_sha1_cx is not None \
|
||||
and self._dep_text_ll_exists(pool, cand_sha1_cx) != 0:
|
||||
cand_ret_cx: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||||
pool, cand_sha1_cx, cand_name, method_name)
|
||||
if cand_ret_cx is not None:
|
||||
mixin_hit = 1
|
||||
mixin_ret_ty = cand_ret_cx
|
||||
mixin_anc_name = cand_name
|
||||
mixin_anc_sha1 = cand_sha1_cx
|
||||
sc_i += 1
|
||||
# 兄弟 Mixin 兜底仅对"接收者类属于当前模块"的场景适用:self 调用兄弟
|
||||
# Mixin 方法时接收者是本类(与候选兄弟类同模块)。接收者类是跨模块类
|
||||
# (如 self.Gen.TypeGenResolve 的 TypeGenResolve,定义在另一模块)时,
|
||||
# 其方法必须经该类自身模块(text.ll/vpi)解析——若本模块恰好定义了
|
||||
# 同名方法 {Cand}.{method},本兜底会误绑定:最坏情况绑定到正在编译的
|
||||
# 函数自身 → ImportsGenMixin.set_current_file 内 self.Gen.TypeGenResolve.
|
||||
# set_current_file(...) 被编译成自调用 → 无限递归 stack-overflow
|
||||
# (二代编 FuncTest 崩溃根因)。接收者类模块无法确定时保持原行为。
|
||||
sib_recv_local: int = 1
|
||||
if trans is not None and trans.ModuleSha1 is not None:
|
||||
sib_recv_sha1: str = None
|
||||
if mc_entry is not None and mc_entry.ModuleSha1 is not None:
|
||||
sib_recv_sha1 = mc_entry.ModuleSha1
|
||||
else:
|
||||
sib_recv_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if sib_recv_sha1 is not None:
|
||||
if string.strcmp(sib_recv_sha1, trans.ModuleSha1) != 0:
|
||||
sib_recv_local = 0
|
||||
if sib_recv_local != 0:
|
||||
sc_i: int = 0
|
||||
sc_n: int = self.Gen.StructGen.get_struct_count()
|
||||
while sc_i < sc_n and found_func is None and mixin_hit == 0:
|
||||
cand_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen._get_struct_entry(sc_i)
|
||||
if cand_entry is not None and cand_entry.Name is not None:
|
||||
cand_name: str = cand_entry.Name
|
||||
if string.strcmp(cand_name, class_name) != 0:
|
||||
# 泛型特化类名含 '['(list[...]/dict[...]):跳过,
|
||||
# 不是兄弟 Mixin 候选(见上方注释)
|
||||
if string.strchr(cand_name, '[') is not None:
|
||||
sc_i += 1
|
||||
continue
|
||||
cand_lookup: str = pool.alloc(128)
|
||||
if cand_lookup is not None:
|
||||
viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name)
|
||||
cand_func: llvmlite.Function | t.CPtr = self.find_func_in_module(
|
||||
mod, cand_lookup)
|
||||
if cand_func is not None:
|
||||
found_func = cand_func
|
||||
mc_anc = cand_name
|
||||
else:
|
||||
# 跨模块 Mixin(定义类在另一文件,本地 IR 无 define):
|
||||
# 用候选类模块 sha1 查 text.ll 返回类型,命中即锁定定义类,
|
||||
# 后续 ret_anc_* 据此构造 {sha1}.{class}.{method} 调用名。
|
||||
# 否则 ret_anc_sha1 停在调用类自身 sha1,_dep_text_ll_exists
|
||||
# 查自身 text.ll(Phase A 翻译中未生成)→ 永久 pending 死锁
|
||||
# (ClassGenVTable._mangle_name → 7871cc1aabebfc33 根因)。
|
||||
if mixin_hit == 0:
|
||||
cand_sha1_cx: str = self.Gen.StructGen.get_struct_sha1(cand_name)
|
||||
if cand_sha1_cx is not None \
|
||||
and self._dep_text_ll_exists(pool, cand_sha1_cx) != 0:
|
||||
cand_ret_cx: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||||
pool, cand_sha1_cx, cand_name, method_name)
|
||||
if cand_ret_cx is not None:
|
||||
mixin_hit = 1
|
||||
mixin_ret_ty = cand_ret_cx
|
||||
mixin_anc_name = cand_name
|
||||
mixin_anc_sha1 = cand_sha1_cx
|
||||
sc_i += 1
|
||||
|
||||
# 确定调用名(默认 "ClassName.method";found_func 未命中时沿 MRO 用
|
||||
# 方法实际定义类的 SHA1 构造,如 Module.append → AST 定义的 append,
|
||||
@@ -1178,8 +1316,10 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
break
|
||||
arg_val_k: llvmlite.Value | t.CPtr = None
|
||||
if arg_node_k is not None:
|
||||
# 先取形参类型(char 字面量 → str 形参需物化字符串,见 translate_constant)
|
||||
pty_k0: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
|
||||
arg_val_k = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg_node_k, None, 0, trans)
|
||||
builder, pool, mod, arg_node_k, None, 0, trans, pty_k0)
|
||||
if arg_val_k is None:
|
||||
# 缺失参数:零值兜底(保持参数数量匹配)。
|
||||
# kw 省略的形参可能有默认值(查不到默认表 ≠ 无默认值),
|
||||
@@ -1204,15 +1344,13 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg_node is None:
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg_node, None, 0, trans)
|
||||
if arg_val is None:
|
||||
continue
|
||||
# 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
|
||||
# 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT)
|
||||
# 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃
|
||||
# 先取形参类型:单引号单字符字面量(CONST_CHAR)传给 str/指针
|
||||
# 形参时需物化 1 字符字符串(translate_constant 依据 target_ty 判定),
|
||||
# 否则 coerce inttoptr 把字符值当指针 → strlen 访问低地址崩溃。
|
||||
pp: llvmlite.Param | t.CPtr = None
|
||||
pty: llvmlite.LLVMType | t.CPtr = None
|
||||
if found_func is not None:
|
||||
pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
pp = llvmlite.function_get_param_head(found_func)
|
||||
pi: int = 0
|
||||
while pp is not None and pi < ai + 1:
|
||||
if pi == ai + 1:
|
||||
@@ -1220,10 +1358,18 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
pp = llvmlite.param_get_next(pp)
|
||||
pi += 1
|
||||
if pp is not None:
|
||||
pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp)
|
||||
if pty is not None:
|
||||
arg_val = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, arg_val, pty, arg_node)
|
||||
pty = llvmlite.param_get_ty(pp)
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg_node, None, 0, trans, pty)
|
||||
if arg_val is None:
|
||||
continue
|
||||
# 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
|
||||
# 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT)
|
||||
# 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃
|
||||
if found_func is not None:
|
||||
if pty is not None:
|
||||
arg_val = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, arg_val, pty, arg_node)
|
||||
else:
|
||||
# found_func=None(跨模块 stub 未注入):数组实参按 C 语义
|
||||
# 衰减为元素指针(对齐 TPC _decay_array_to_ptr)。否则
|
||||
@@ -1270,6 +1416,53 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
mdf_default_count = mdf_gd.DefaultCount
|
||||
mdf_param_count = mdf_gd.ParamCount
|
||||
|
||||
# 跨模块 stub 未注入兜底:如 self.Gen.ExprGenCdef.method 经 Generator
|
||||
# 属性访问调用依赖模块方法,依赖收集不加载其 vpi → 函数表无
|
||||
# ParamCount/默认参数 → 调用点缺参 → 被调函数读栈残留
|
||||
# (IterTest 跨模块 CDefine 查找 depth=160 假递归根因)。用 vpi
|
||||
# 文本缓存补全参数数,下方默认参数填充(含零值兜底)随即生效,
|
||||
# declare/call 与 define 参数数对齐。
|
||||
vpi_pa: str = None
|
||||
if mdf_param_count == 0 and found_func is None:
|
||||
vpi_sha1_p: str = None
|
||||
if mc_entry is not None and mc_entry.ModuleSha1 is not None:
|
||||
vpi_sha1_p = mc_entry.ModuleSha1
|
||||
else:
|
||||
vpi_sha1_p = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if vpi_sha1_p is not None:
|
||||
vpi_pa = self.Gen.CallGenBase._vpi_method_param_annot(
|
||||
pool, vpi_sha1_p, class_name, method_name)
|
||||
if vpi_pa is not None and vpi_pa[0] != '\0':
|
||||
vpi_pc2: int = 1
|
||||
vi2: t.CSizeT = 0
|
||||
while vpi_pa[vi2] != '\0':
|
||||
if vpi_pa[vi2] == '@':
|
||||
vpi_pc2 += 1
|
||||
vi2 += 1
|
||||
mdf_param_count = vpi_pc2 - 1 # 非 self 参数数
|
||||
|
||||
# [修复 2026-08-25] found_func 参数数回退:函数表/默认表无 ParamCount
|
||||
# (mdf_param_count==0)但 found_func(模块内 declare)已找到时,用其
|
||||
# 参数数作补全基准。缺它:省略默认参数(如 translate_value 的
|
||||
# target_ty=None)的调用补全不触发 → call 实参(8) < define 形参(9)
|
||||
# → x64 ABI 第 9 参读栈残留垃圾 → is_ptr_type(0x40) 崩溃(SlotsBugTest
|
||||
# 二代编 translate_assign/AugAssign 崩溃根因)。
|
||||
# 排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__):含 raise 方法
|
||||
# 定义尾部注入 2 个 EH 形参,计入会让补全先补 zeroinitializer 占位,
|
||||
# _emit_eh_guarded_call 再追加真实 EH 实参 → 双重注入(TestFBProject
|
||||
# raise_disk() 崩溃同源,与 _call_method_on_ptr/CallGenMixin 一致)。
|
||||
if mdf_param_count == 0 and found_func is not None:
|
||||
ppcnt_f: int = 0
|
||||
ppn_f: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
while ppn_f is not None:
|
||||
fp_nm_f: str = llvmlite.param_get_name(ppn_f)
|
||||
if fp_nm_f is None or (string.strcmp(fp_nm_f, "%__eh_msg_out__") != 0
|
||||
and string.strcmp(fp_nm_f, "%__eh_code_out__") != 0):
|
||||
ppcnt_f += 1
|
||||
ppn_f = llvmlite.param_get_next(ppn_f)
|
||||
if ppcnt_f > 1:
|
||||
mdf_param_count = ppcnt_f - 1 # 非 self 非 EH 参数数
|
||||
|
||||
# 计算需要填充的参数(不含 self)
|
||||
# arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建)
|
||||
# mdf_param_count = 函数定义的非 self 参数数量
|
||||
@@ -1317,6 +1510,40 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
llvmlite.value_set_next(tail, zero_val)
|
||||
tail = zero_val
|
||||
total_count += 1
|
||||
elif vpi_pa is not None:
|
||||
# found_func 为 None(stub 未注入):用 vpi 参数注解解析
|
||||
# 缺失参数类型(段索引 mdf_pi+1,跳过首参 self 空段),
|
||||
# 值取类型零值(默认参数值恰为零值;查不到 ≠ 无默认值)。
|
||||
seg_idx_v: int = mdf_pi + 1
|
||||
seg_no_v: int = 0
|
||||
seg_cur_v: t.CSizeT = 0
|
||||
while seg_no_v < seg_idx_v and vpi_pa[seg_cur_v] != '\0':
|
||||
if vpi_pa[seg_cur_v] == '@':
|
||||
seg_no_v += 1
|
||||
seg_cur_v += 1
|
||||
seg_start_v: t.CSizeT = seg_cur_v
|
||||
seg_len_v: t.CSizeT = 0
|
||||
while vpi_pa[seg_start_v + seg_len_v] != '\0' \
|
||||
and vpi_pa[seg_start_v + seg_len_v] != '@':
|
||||
seg_len_v += 1
|
||||
if seg_no_v == seg_idx_v:
|
||||
pty_v: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if seg_len_v > 0:
|
||||
seg_buf_v: bytes = stdlib.malloc(seg_len_v + 1)
|
||||
if seg_buf_v is not None:
|
||||
string.strncpy(seg_buf_v, vpi_pa + seg_start_v, seg_len_v)
|
||||
seg_buf_v[seg_len_v] = '\0'
|
||||
rty_v: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenBase._vpi_resolve_param_annot_ty(
|
||||
pool, seg_buf_v)
|
||||
if rty_v is not None:
|
||||
pty_v = rty_v
|
||||
stdlib.free(seg_buf_v)
|
||||
zero_val_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, pty_v)
|
||||
if zero_val_v is not None:
|
||||
llvmlite.value_set_next(zero_val_v, None)
|
||||
llvmlite.value_set_next(tail, zero_val_v)
|
||||
tail = zero_val_v
|
||||
total_count += 1
|
||||
mdf_pi += 1
|
||||
|
||||
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
|
||||
@@ -1508,12 +1735,11 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
arg_node_sp: ast.AST | t.CPtr = cargs_sp.get(ai_sp)
|
||||
if arg_node_sp is None:
|
||||
continue
|
||||
arg_val_sp: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg_node_sp, None, 0, trans)
|
||||
if arg_val_sp is None:
|
||||
continue
|
||||
# 先取形参类型(char 字面量 → str 形参需物化字符串,见 translate_constant)
|
||||
pp_sp: llvmlite.Param | t.CPtr = None
|
||||
pty_sp: llvmlite.LLVMType | t.CPtr = None
|
||||
if found_func is not None:
|
||||
pp_sp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
pp_sp = llvmlite.function_get_param_head(found_func)
|
||||
pi_sp: int = 0
|
||||
while pp_sp is not None and pi_sp < ai_sp + 1:
|
||||
if pi_sp == ai_sp + 1:
|
||||
@@ -1521,10 +1747,14 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
pp_sp = llvmlite.param_get_next(pp_sp)
|
||||
pi_sp += 1
|
||||
if pp_sp is not None:
|
||||
pty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_sp)
|
||||
if pty_sp is not None:
|
||||
arg_val_sp = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, arg_val_sp, pty_sp, arg_node_sp)
|
||||
pty_sp = llvmlite.param_get_ty(pp_sp)
|
||||
arg_val_sp: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg_node_sp, None, 0, trans, pty_sp)
|
||||
if arg_val_sp is None:
|
||||
continue
|
||||
if pty_sp is not None:
|
||||
arg_val_sp = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, arg_val_sp, pty_sp, arg_node_sp)
|
||||
else:
|
||||
# found_func=None:数组实参按 C 语义衰减为元素指针
|
||||
# (与 _translate_method_call 一致,避免 declare 类型不匹配)
|
||||
|
||||
Reference in new issue
Block a user