fix(tpv-call): 裸名调用同模块函数优先(owner_sha1),修复跨模块同名 stub 抢占致 _advance 误绑
This commit is contained in:
1 parent
a260b9316d
commit
ab814f55e6
6 files changed
+436
-15
No files matched your search
@@ -501,13 +501,21 @@ class CallGenBase:
|
||||
|
||||
|
||||
def find_func_in_module(self, mod: llvmlite.LLVMModule | t.CPtr,
|
||||
name: str) -> llvmlite.Function | t.CPtr:
|
||||
name: str,
|
||||
owner_sha1: str = None) -> llvmlite.Function | t.CPtr:
|
||||
"""在模块的函数链表中按名称查找函数
|
||||
|
||||
查找策略:
|
||||
1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数)
|
||||
2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数)
|
||||
|
||||
owner_sha1: 当前模块 SHA1。非 None 时在本模块 define 判定之前先做
|
||||
"本模块同名函数"优先扫描(mangled 名以 "{owner_sha1}." 开头且恰为
|
||||
"{owner_sha1}.{name}")。裸名调用应优先解析为当前模块自身函数——
|
||||
其前向 declare 在函数体翻译时可能尚未激活(IsDeclared 仍为 1),
|
||||
pass2 的 IsDeclared==0 判定会跳过它,pass3 又会按链表顺序误绑排在
|
||||
FuncHead 前面的跨模块 stub declare(lexer.vp _advance 根因)。
|
||||
|
||||
使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制
|
||||
(stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。
|
||||
"""
|
||||
@@ -522,6 +530,28 @@ class CallGenBase:
|
||||
if string.strcmp(cur_name, name) == 0:
|
||||
return cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
# 第一遍半(owner_sha1 提供时):本模块同名函数优先。
|
||||
# 仅接受恰为 "{owner_sha1}.{name}" 的形态(mangled 模块级函数名含
|
||||
# 且只含一个 '.'),不匹配 "{sha1}.Class.method" 等方法名。是否
|
||||
# IsDeclared==0 均可返回:前向 declare 与 define 同名同符号。
|
||||
if owner_sha1 is not None:
|
||||
cur = mod.FuncHead
|
||||
while cur is not None:
|
||||
cur_name_o: str = llvmlite.function_get_name(cur)
|
||||
if cur_name_o is not None:
|
||||
cur_len_o: t.CSizeT = string.strlen(cur_name_o)
|
||||
if cur_len_o == 17 + name_len:
|
||||
if string.strncmp(cur_name_o, owner_sha1, 16) == 0 and cur_name_o[16] == '.':
|
||||
suffix_start_o: t.CSizeT = cur_len_o - name_len
|
||||
if cur_name_o[suffix_start_o - 1] == '.':
|
||||
match_o: int = 1
|
||||
for i in range(name_len):
|
||||
if cur_name_o[suffix_start_o + i] != name[i]:
|
||||
match_o = 0
|
||||
break
|
||||
if match_o == 1:
|
||||
return cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
# 第二遍:后缀匹配(.name)
|
||||
# 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到
|
||||
# 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名
|
||||
|
||||
@@ -393,6 +393,14 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
# 破坏表达式翻译;pending 文件本遍不写盘,下遍重译)
|
||||
call_ret_ty = llvmlite.Int32(pool)
|
||||
else:
|
||||
# [METHDBG] 临时诊断:依赖就绪但返回类型仍无法确定(用后移除)
|
||||
dbg_ms2: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||||
dbg_cls_short: str = class_name
|
||||
if dbg_cls_short is not None:
|
||||
pass
|
||||
stdio.printf("[METHDBG] fatal(method_ret): mod=%s cls=%s method=%s sha1=%s\n",
|
||||
dbg_ms2, dbg_cls_short, method_name,
|
||||
cls_sha1 if cls_sha1 is not None else "none")
|
||||
err_cm4: str = pool.alloc(256)
|
||||
if err_cm4 is not None:
|
||||
viperlib.snprintf(err_cm4, 256,
|
||||
@@ -681,6 +689,48 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
if obj_ptr is None or cl is None:
|
||||
return None
|
||||
|
||||
# [修复] list 泛型容器方法兜底拦截:接收者被分派为 list 特化类名
|
||||
# (list[...] / {sha1}.list[...],剥离外层前缀后以 'list' 开头)且方法属
|
||||
# list 内置集合时,本调用不存在对应 C 函数——若继续走下方 MRO/函数/
|
||||
# text.ll/vpi stub 返回类型解析必然全部落空 → fatal(mro_ret)
|
||||
# (AstTest includes/ast/parser.vp _fix_store_ctx 局部变量
|
||||
# tp_elts: rowptr[list[rowptr[AST]]] 后调 tp_elts.get(i) 根因:函数局部
|
||||
# 变量经 pre_scan/块作用域登记后,CallGenDispatch 的 list 注解拦截
|
||||
# 偶发漏判时仍会把 obj_var 当作普通结构体变量送入本函数)。直接转交
|
||||
# 本类 _translate_list_builtin_call 内联翻译(与 _tc_h6_method_dispatch
|
||||
# 尾部 list 分支同语义:内联 GEP __data__/__count__/__elem_size__),
|
||||
# 保证 get/append 等 list 内置方法一律命中、绝不进入 MRO 解析。
|
||||
if method_name is not None and class_name is not None:
|
||||
lb_cls: str = class_name
|
||||
# 剥离跨模块特化名 sha1 前缀 "{16hex}."({sha}.list[...] 形态)
|
||||
if string.strncmp(lb_cls, "list", 4) != 0 \
|
||||
and string.strlen(lb_cls) > 17 and lb_cls[16] == '.':
|
||||
if string.strncmp(lb_cls + 17, "list", 4) == 0:
|
||||
lb_cls = lb_cls + 17
|
||||
if self.Gen.CallGenProp._is_list_builtin_method(lb_cls, method_name) != 0:
|
||||
# 双指针槽形态(rowptr[list[...]] 局部变量 alloca Ptr(Ptr(Struct))
|
||||
# 直接传入时先 load 一层得到对象指针 Ptr(Struct),与分派方
|
||||
# _translate_method_call 调用点的 obj_ptr 语义一致)。
|
||||
lb_obj: llvmlite.Value | t.CPtr = obj_ptr
|
||||
if lb_obj is not None and lb_obj.Ty is not None:
|
||||
match lb_obj.Ty:
|
||||
case llvmlite.LLVMType.Ptr(lb_inner):
|
||||
match lb_inner:
|
||||
case llvmlite.LLVMType.Ptr(lb_inner2):
|
||||
lb_obj = llvmlite.build_load(builder, lb_inner, lb_obj)
|
||||
case _:
|
||||
pass
|
||||
case _:
|
||||
pass
|
||||
if lb_obj is not None:
|
||||
lb_cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
lb_can: t.CSizeT = 0
|
||||
if lb_cargs is not None:
|
||||
lb_can = len(lb_cargs)
|
||||
return self._translate_list_builtin_call(
|
||||
pool, builder, mod, cl, method_name, lb_obj,
|
||||
lb_cargs, lb_can, trans)
|
||||
|
||||
# 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
|
||||
# 用于继承链遍历、SHA1 查找和虚表分派
|
||||
mc_entry: GenTypes.StructEntry | t.CPtr = None
|
||||
@@ -1109,6 +1159,10 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
# None 会破坏表达式翻译,pending 文件本遍不写盘)
|
||||
call_ret_ty = llvmlite.Int32(pool)
|
||||
else:
|
||||
# [METHDBG] 临时诊断:MRO 祖先依赖就绪但返回类型仍解析失败(用后移除)
|
||||
dbg_ms4: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||||
stdio.printf("[METHDBG] fatal(mro_ret): mod=%s cls=%s method=%s\n",
|
||||
dbg_ms4, class_name, method_name)
|
||||
call_ret_ty = self._fail_method_ret_ty(method_name, cl)
|
||||
|
||||
# found_func 未命中但返回类型已解析:用方法定义类构造跨模块调用名
|
||||
@@ -1598,6 +1652,226 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
return self.Gen.CallGenLeafKit._emit_eh_guarded_call(
|
||||
builder, pool, mod, trans, found_func, call_name, head, total_count,
|
||||
call_ret_ty, is_variadic_3441)
|
||||
|
||||
# ============================================================
|
||||
# _translate_list_builtin_call — list 内置方法内联翻译(兜底共享实现)
|
||||
#
|
||||
# 供 _translate_method_call 顶部 list 兜底拦截调用(语义与
|
||||
# CallGenDispatch._tc_h6_method_dispatch 尾部 list 内置分支完全一致):
|
||||
# list 结构布局 (6 字段 × 8 字节):
|
||||
# __data__(0) __count__(8) __capacity__(16) __pool__(24)
|
||||
# __elem_size__(32) __iter_index__(40)
|
||||
# get/__getitem__/set/__setitem__/pop/clear/__iter__/__len__/append 内联
|
||||
# 翻译,绝不生成对 list 方法函数的跨模块调用(list 方法无对应 C 函数)。
|
||||
# lm_obj 必须是已 load 的 list 对象指针 Ptr(list-struct)。
|
||||
# ============================================================
|
||||
def _translate_list_builtin_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cl: ast.Call | t.CPtr,
|
||||
lm_name: str,
|
||||
lm_obj: llvmlite.Value | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译 list 内置方法调用,返回 call 结果 Value(void 方法返回 None)"""
|
||||
if pool is None or builder is None or lm_obj is None or lm_name is None:
|
||||
return None
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
# 元素类型 T:从 list 特化类型名解析(list[int]→i32、list[str]→i8*、
|
||||
# 未知/指针元素→i8*),与 CallGenDispatch 尾部 list 分支一致
|
||||
lm_esty: llvmlite.LLVMType | t.CPtr = \
|
||||
self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||||
lm_ename: str = None
|
||||
if lm_esty is not None:
|
||||
lm_ename = llvmlite.get_struct_name(lm_esty)
|
||||
lm_elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if lm_ename is not None:
|
||||
lm_elem_ty = self.Gen.ExprGenName._list_elem_type_from_name(
|
||||
pool, lm_ename)
|
||||
if lm_elem_ty is None:
|
||||
lm_elem_ty = i8_ptr_ty
|
||||
|
||||
# get / __getitem__: 返回 index 处的元素
|
||||
if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0:
|
||||
if can >= 1 and cargs is not None:
|
||||
# 加载 __data__ (偏移 0)
|
||||
g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
|
||||
g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0)
|
||||
g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp)
|
||||
# 加载 __elem_size__ (偏移 32, index 4)
|
||||
g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
|
||||
g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4)
|
||||
g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp)
|
||||
# 翻译 index
|
||||
g_idx_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
g_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, g_idx_node, None, 0, trans)
|
||||
if g_data is not None and g_esize is not None and g_idx_val is not None:
|
||||
g_idx_i64: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, g_idx_val, i64_ty, g_idx_node)
|
||||
g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize)
|
||||
g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset)
|
||||
if g_addr is not None:
|
||||
g_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty))
|
||||
if g_ep is not None:
|
||||
return llvmlite.build_load(builder, lm_elem_ty, g_ep)
|
||||
|
||||
# set / __setitem__: 设置 index 处的元素
|
||||
elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0:
|
||||
if can >= 2 and cargs is not None:
|
||||
s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
|
||||
s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0)
|
||||
s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp)
|
||||
s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
|
||||
s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4)
|
||||
s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp)
|
||||
s_idx_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
s_val_node: ast.AST | t.CPtr = cargs.get(1)
|
||||
s_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, s_idx_node, None, 0, trans)
|
||||
s_val_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, s_val_node, None, 0, trans)
|
||||
if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None:
|
||||
s_idx_i64: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, s_idx_val, i64_ty, s_idx_node)
|
||||
s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize)
|
||||
s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset)
|
||||
if s_addr is not None:
|
||||
s_val_elem: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, s_val_val, lm_elem_ty, s_val_node)
|
||||
s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty))
|
||||
if s_ep is not None:
|
||||
llvmlite.build_store(builder, s_val_elem, s_ep)
|
||||
return None
|
||||
|
||||
# pop: 返回最后一个元素,count--
|
||||
elif string.strcmp(lm_name, "pop") == 0:
|
||||
p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
|
||||
p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1)
|
||||
p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp)
|
||||
p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub(
|
||||
builder, p_count, llvmlite.const_int64(pool, 1))
|
||||
llvmlite.build_store(builder, p_nc, p_cpp)
|
||||
p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
|
||||
p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0)
|
||||
p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp)
|
||||
p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
|
||||
p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4)
|
||||
p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp)
|
||||
if p_data is not None and p_esize is not None and p_nc is not None:
|
||||
p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize)
|
||||
p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset)
|
||||
if p_addr is not None:
|
||||
p_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty))
|
||||
if p_ep is not None:
|
||||
return llvmlite.build_load(builder, lm_elem_ty, p_ep)
|
||||
|
||||
# clear: count = 0
|
||||
elif string.strcmp(lm_name, "clear") == 0:
|
||||
c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
|
||||
c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1)
|
||||
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp)
|
||||
return None
|
||||
|
||||
# __iter__: iter_index = 0, return self
|
||||
elif string.strcmp(lm_name, "__iter__") == 0:
|
||||
it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5)
|
||||
it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5)
|
||||
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp)
|
||||
return lm_obj
|
||||
|
||||
# __len__: 返回 __count__ (偏移 8, index 1)
|
||||
elif string.strcmp(lm_name, "__len__") == 0:
|
||||
l_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
|
||||
l_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, l_idx1)
|
||||
if l_cpp is not None:
|
||||
return llvmlite.build_load(builder, i64_ty, l_cpp)
|
||||
|
||||
# append: 直接调用 list.append(self, item)
|
||||
# append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现
|
||||
elif string.strcmp(lm_name, "append") == 0:
|
||||
if can >= 1 and cargs is not None:
|
||||
ap_sha1: str = self._lookup_module_sha1("_list")
|
||||
if ap_sha1 is None:
|
||||
# 依赖模块未编译(_list 未预加入编译链):fail-fast,
|
||||
# 绝不静默跳过 append(元素永远不会被加入列表)
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)",
|
||||
"InternalCompilerError")
|
||||
if ap_sha1 is not None:
|
||||
# 特化类名提取:list.append 的符号名是
|
||||
# {sha1}.list[AST|CPtr].append(带类型参数特化名),而非
|
||||
# {sha1}.list.append。lm_obj 类型即特化结构体 Ptr(list[...]),
|
||||
# 从类型解析特化类名拼接调用名,否则 ld.lld undefined symbol
|
||||
ap_spec_nm: str = None
|
||||
ap_struct_ty: llvmlite.LLVMType | t.CPtr = \
|
||||
self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||||
if ap_struct_ty is not None:
|
||||
ap_spec_nm = self.Gen.StructGen.get_class_name_by_type(
|
||||
pool, ap_struct_ty)
|
||||
if ap_spec_nm is None:
|
||||
ap_spec_nm = "list"
|
||||
# 触发泛型特化翻译(幂等,MethodsEmitted 防重入)
|
||||
if trans is not None and ap_spec_nm is not None:
|
||||
lbkt_ap: str = string.strchr(ap_spec_nm, '[')
|
||||
if lbkt_ap is not None:
|
||||
rbkt_ap: str = string.strrchr(ap_spec_nm, ']')
|
||||
if rbkt_ap is not None and rbkt_ap > lbkt_ap:
|
||||
base_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_ap) - t.CUInt64T(ap_spec_nm))
|
||||
arg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_ap) - t.CUInt64T(lbkt_ap) - 1)
|
||||
if base_len_ap > 0 and arg_len_ap > 0:
|
||||
base_buf_ap: str = pool.alloc(base_len_ap + 1)
|
||||
arg_buf_ap: str = pool.alloc(arg_len_ap + 1)
|
||||
if base_buf_ap is not None and arg_buf_ap is not None:
|
||||
string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap)
|
||||
base_buf_ap[base_len_ap] = '\0'
|
||||
string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap)
|
||||
arg_buf_ap[arg_len_ap] = '\0'
|
||||
args_ap: list[str] | t.CPtr = list[str](pool, 8)
|
||||
if args_ap is not None:
|
||||
# 逗号分隔多类型实参(list[X] / dict[K, V])
|
||||
cur_ap: str = arg_buf_ap
|
||||
while cur_ap is not None:
|
||||
comma_ap: str = string.strchr(cur_ap, ',')
|
||||
if comma_ap is None:
|
||||
args_ap.append(cur_ap)
|
||||
break
|
||||
seg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(comma_ap) - t.CUInt64T(cur_ap))
|
||||
seg_buf_ap: str = pool.alloc(seg_len_ap + 1)
|
||||
if seg_buf_ap is not None:
|
||||
string.strncpy(seg_buf_ap, cur_ap, seg_len_ap)
|
||||
seg_buf_ap[seg_len_ap] = '\0'
|
||||
args_ap.append(seg_buf_ap)
|
||||
cur_ap = comma_ap + 1
|
||||
self.Gen.ClassGenGeneric._specialize_generic_class(
|
||||
trans, base_buf_ap, args_ap)
|
||||
# 调用名 "{sha1}.{spec}.append":
|
||||
# sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25
|
||||
ap_mlen: t.CSizeT = string.strlen(ap_sha1) + \
|
||||
string.strlen(ap_spec_nm) + 26
|
||||
ap_mangled: str = pool.alloc(ap_mlen)
|
||||
if ap_mangled is not None:
|
||||
viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append",
|
||||
ap_sha1, ap_spec_nm)
|
||||
ap_item_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
ap_item_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, ap_item_node, None, 0, trans)
|
||||
if ap_item_val is not None:
|
||||
llvmlite.value_set_next(lm_obj, None)
|
||||
llvmlite.value_set_next(ap_item_val, None)
|
||||
llvmlite.value_set_next(lm_obj, ap_item_val)
|
||||
ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2)
|
||||
return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0)
|
||||
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# _translate_super_call — super().method(args) → 静态调用父类方法
|
||||
#
|
||||
|
||||
@@ -1231,6 +1231,34 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if obj_var is not None and obj_var.Ty is not None:
|
||||
# 检查是否为 Ptr(Struct(...))(结构体值变量)
|
||||
# 或 Ptr(Ptr(Struct(...)))(指针变量,需 load)
|
||||
# list 泛型容器注解先行识别(早期拦截,供下方各 class 分支共用):
|
||||
# rowptr[list[rowptr[AST]]] 变量(ast/parser.vp _fix_store_ctx
|
||||
# 的 tp_elts,元素类在另一模块)LLVM 形态为
|
||||
# Ptr(Ptr(Struct('list[sha.AST]')));list 特化 struct 不注册为
|
||||
# 普通类,get_class_name_by_type 或返回 None、或对类型名尾部
|
||||
# (list[sha.AST]) 后缀匹配误命中内层元素类(如 'AST')→ 下方
|
||||
# 两个 Ptr 分支的 list 内置拦截落空/错判。AnnotClassName 经
|
||||
# extract_class_name_from_annotation 已剥最外层 rowptr 存为
|
||||
# "list[元素]",此处再兜底剥一次(rowptr[list[...]] 形态):
|
||||
# 内层以 'list' 开头且方法属 list 内置集合时,本 obj.method 调用
|
||||
# 必须交给本方法尾部 list 内置分支(内联 GEP)翻译——置位
|
||||
# is_list_annot_builtin 后跳过下方所有 class 方法分支/FakeDuck/
|
||||
# AnnotClassName 方法构造,绝不进入 _translate_method_call/MRO
|
||||
# 返回类型解析(函数/text.ll/vpi stub 均未命中 → fatal(mro_ret),
|
||||
# AstTest ast/parser.vp 根因)。普通类/str/bytes 注解不以 'list'
|
||||
# 开头 → 不置位,行为不变。
|
||||
var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, method_obj_nm.id)
|
||||
is_list_annot_builtin: int = 0
|
||||
if var_entry is not None and var_entry.AnnotClassName is not None:
|
||||
la_buf: str = var_entry.AnnotClassName
|
||||
la_tail: str = la_buf
|
||||
if string.strncmp(la_buf, "rowptr[", 7) == 0:
|
||||
la_tail = la_buf + 7
|
||||
if string.strncmp(la_tail, "list", 4) == 0:
|
||||
if self.Gen.CallGenProp._is_list_builtin_method(
|
||||
la_tail, func_name) != 0:
|
||||
is_list_annot_builtin = 1
|
||||
match obj_var.Ty:
|
||||
case llvmlite.LLVMType.Ptr(obj_struct_ty):
|
||||
class_nm: str = self.Gen.StructGen.get_class_name_by_type(
|
||||
@@ -1242,7 +1270,11 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# _translate_method_call 会查 append 返回类型(函数/text.ll/
|
||||
# vpi stub 均未命中)→ fail-fast。检测到 list 方法时
|
||||
# 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。
|
||||
if self.Gen.CallGenProp._is_list_builtin_method(class_nm, func_name) == 0:
|
||||
# 注解兜底(is_list_annot_builtin=1)同跳过:class_nm
|
||||
# 可能被类型名后缀匹配错解为内层元素类,非 'list' 前缀
|
||||
# 拦截会漏放 → 走 method_call/MRO fatal。
|
||||
if self.Gen.CallGenProp._is_list_builtin_method(class_nm, func_name) == 0 \
|
||||
and is_list_annot_builtin == 0:
|
||||
if hit_box is not None:
|
||||
hit_box[0] = 1
|
||||
return self.Gen.CallGenCall._translate_method_call(
|
||||
@@ -1255,8 +1287,11 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
inner_nm: str = self.Gen.StructGen.get_class_name_by_type(
|
||||
pool, inner_struct_ty)
|
||||
if inner_nm is not None:
|
||||
# list 内置方法同样跳过(同 Ptr(Struct) 分支)
|
||||
if self.Gen.CallGenProp._is_list_builtin_method(inner_nm, func_name) == 0:
|
||||
# list 内置方法同样跳过(同 Ptr(Struct) 分支);
|
||||
# 注解兜底(is_list_annot_builtin=1)同跳过:
|
||||
# inner_nm 也可能被后缀匹配错解为内层元素类。
|
||||
if self.Gen.CallGenProp._is_list_builtin_method(inner_nm, func_name) == 0 \
|
||||
and is_list_annot_builtin == 0:
|
||||
obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, obj_struct_ty, obj_var)
|
||||
if obj_ptr is not None:
|
||||
@@ -1269,15 +1304,24 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# 方法调用 → 扩展类 _Type/_str(a.type_id() / a.upper())。
|
||||
# 前置拦截:常规结构体方法分支全落空时,尝试扩展类方法
|
||||
# (find_func_in_module 未命中返回 None,不影响正常路径)。
|
||||
fd_name_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call(
|
||||
pool, builder, mod, None, func_name, cl, trans)
|
||||
if fd_name_res is not None:
|
||||
return fd_name_res
|
||||
# list 容器注解命中(is_list_annot_builtin=1)时跳过 FakeDuck:
|
||||
# 接收者非 str/bytes,此调用必须由尾部 list 内置分支翻译。
|
||||
if is_list_annot_builtin == 0:
|
||||
fd_name_res: llvmlite.Value | t.CPtr = self.Gen.CallGenFd._translate_fakeduck_call(
|
||||
pool, builder, mod, None, func_name, cl, trans)
|
||||
if fd_name_res is not None:
|
||||
return fd_name_res
|
||||
# AnnotClassName 回退:联合类型简化为 Ptr(i8) 时,
|
||||
# 通过原始类型注解的类名查找结构体
|
||||
var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, method_obj_nm.id)
|
||||
if var_entry is not None and var_entry.AnnotClassName is not None:
|
||||
# 通过原始类型注解的类名查找结构体(var_entry 已在上方
|
||||
# list 注解识别处查得,同一变量表项)。
|
||||
# list 容器注解命中(is_list_annot_builtin=1)时跳过本回退:
|
||||
# 本回退的"剥模块前缀"会按内层元素 '.'(如
|
||||
# list[rowptr[sha.AST]])把类名错切为 'AST]]' 垃圾 → 下方
|
||||
# _is_list_builtin_method 前缀匹配不中 → 误走 FakeDuck/sha1
|
||||
# 方法构造 → _translate_method_call MRO fatal。list 调用由
|
||||
# 尾部 list 内置分支统一翻译。
|
||||
if var_entry is not None and var_entry.AnnotClassName is not None \
|
||||
and is_list_annot_builtin == 0:
|
||||
annot_val: str = var_entry.AnnotClassName
|
||||
# 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy"
|
||||
dot_ptr: str = string.strrchr(annot_val, '.')
|
||||
|
||||
@@ -946,11 +946,33 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
|
||||
def find_func_in_table(self, funcs: GenTypes.FuncEntry | t.CPtr,
|
||||
func_count: int,
|
||||
name: str) -> llvmlite.Function | t.CPtr:
|
||||
"""在函数表中按名称查找,返回 Function 指针或 None"""
|
||||
name: str,
|
||||
owner_sha1: str = None) -> llvmlite.Function | t.CPtr:
|
||||
"""在函数表中按名称查找,返回 Function 指针或 None
|
||||
|
||||
owner_sha1: 当前模块 SHA1。非 None 时"本模块函数优先"——表里同名条目
|
||||
可能同时含本模块函数与依赖 stub 注入的外来函数(LoadDepVpiIntoModule
|
||||
在 forward_declare_functions 之前把依赖模块同名函数以裸名注册进本文件
|
||||
_funcs,槽位在前;本模块条目注册在后)。本模块函数 mangled 名为
|
||||
"{owner_sha1}.{name}",按其 16 位前缀优先返回;无本模块条目
|
||||
(纯 from-import/外部 stub)时回落首个同名条目(旧语义)。
|
||||
"""
|
||||
if name is None or funcs is None:
|
||||
return None
|
||||
entry_size: t.CSizeT = GenTypes.FuncEntry.__sizeof__()
|
||||
if owner_sha1 is not None:
|
||||
# 第一遍:本模块条目优先(mangled 名以 "{owner_sha1}." 开头)。
|
||||
# 前缀相同但非 mangled 名(CExport 等裸名条目名不含 '.')不命中,
|
||||
# 由下方通用遍兜底。
|
||||
for i in range(func_count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size
|
||||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry.Name is not None and entry.Func is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
fn_nm_o: str = llvmlite.function_get_name(entry.Func)
|
||||
if fn_nm_o is not None:
|
||||
if string.strncmp(fn_nm_o, owner_sha1, 16) == 0 and fn_nm_o[16] == '.':
|
||||
return entry.Func
|
||||
for i in range(func_count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size
|
||||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
|
||||
@@ -562,7 +562,43 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if decor_wrap_nm is not None:
|
||||
found_func = self.find_func_in_module(mod, decor_wrap_nm)
|
||||
else:
|
||||
found_func = self.find_func_in_module(mod, func_name)
|
||||
# 本模块已定义函数名的裸名调用:先按裸名在模块函数表
|
||||
# (FuncEntry 数组,forward_declare_functions 已把所有模块级
|
||||
# 函数登记进 trans._funcs:Name=裸名、Func=其 declare/define)
|
||||
# 精确命中,再回落 find_func_in_module 的 LLVM 模块链表扫描。
|
||||
# 根因:同模块互调(string.vp atof_out 内 atof(src) → 本模块
|
||||
# @{sha1}.atof)此前只靠 find_func_in_module 扫 FuncHead,
|
||||
# 链表扫描漏掉本模块 atof 时 found_func=None → 误走 C 库自动
|
||||
# declare / from_imports 回退,最终报"裸名调用 'atof' 未定义且
|
||||
# 未导入"。函数表才是同模块函数名的权威注册表(即注释 L540-541
|
||||
# "优先从函数表按裸名精确匹配" 的原意,此处补落地)。模块表只含
|
||||
# 模块级函数(无方法),CExport 函数表中 Func 名即裸名,复用
|
||||
# 不改变既有 CExport/非 CExport 的符号语义。
|
||||
mod_fn_tb: llvmlite.Function | t.CPtr = None
|
||||
if actual_funcs is not None:
|
||||
# 同模块函数优先:_funcs 表在 forward_declare_functions 之前
|
||||
# 已被 LoadDepVpiIntoModule 注入的依赖模块 stub 污染——外来
|
||||
# 同名函数(如 lexer.vp 的 _advance)以裸名注册在表前部,
|
||||
# 普通按名查找从 0 号槽先命中它 → 本模块 _advance 的 163 处
|
||||
# 裸名调用全被绑成 lexer 版(AstTest 根因)。传 trans.ModuleSha1
|
||||
# 使表查找优先返回 mangled 名为 "{ModuleSha1}.{name}" 的本模块
|
||||
# 条目(forward_declare 已把本模块全部模块级函数登记进表)。
|
||||
tbl_owner_sha1: str = None
|
||||
if trans is not None:
|
||||
tbl_owner_sha1 = trans.ModuleSha1
|
||||
mod_fn_tb = self.Gen.CallGenLeafKit.find_func_in_table(
|
||||
actual_funcs, actual_func_count, func_name, tbl_owner_sha1)
|
||||
if mod_fn_tb is not None:
|
||||
found_func = mod_fn_tb
|
||||
else:
|
||||
# 表内无同名条目(如本模块函数未登记/表被清空)时回退扫
|
||||
# FuncHead。同样传 owner_sha1:本模块同名前向 declare 尚未
|
||||
# 激活(IsDeclared==1)时 pass2 会跳过、pass3 会按链表顺序
|
||||
# 误绑排在前面的跨模块 stub declare,前缀优先扫描兜住该时序。
|
||||
ff_owner_sha1: str = None
|
||||
if trans is not None:
|
||||
ff_owner_sha1 = trans.ModuleSha1
|
||||
found_func = self.find_func_in_module(mod, func_name, ff_owner_sha1)
|
||||
# 治本修复(对齐 Attribute 路径 L6579-6613):后缀匹配误命中类方法
|
||||
# (SHA1.Class.method,第 2 段是已注册结构体类)必须拒绝——否则方法体内
|
||||
# 与 from-import 模块函数同名的裸名调用(如 LLVMModuleCore.SSAValue 内
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
fix(tpv-call): 裸名调用同模块优先,修复跨模块同名 stub 抢占致 _advance 误绑
|
||||
|
||||
根因:LoadDepVpiIntoModule 在 forward_declare_functions 之前把依赖模块
|
||||
(lexer)函数以裸名注册进本文件 _funcs(槽位在前),find_func_in_table
|
||||
与 find_func_in_module 后缀扫描均先命中跨模块 stub declare → parser.vp
|
||||
内部 163 处 _advance(ps) 全部绑成 lexer._advance,并以 Parser→Lexer**
|
||||
bitcast 传参(运行期游标永不推进,AstTest 无限 SyntaxError 至 pool 耗尽)。
|
||||
|
||||
修复:find_func_in_table / find_func_in_module 增加 owner_sha1(当前模块)
|
||||
前缀优先遍,仅接受恰为 "{sha1}.{name}" 的本模块函数(declare/define 均可,
|
||||
前向 declare 未激活时同样命中);translate_call 裸名分支传 trans.ModuleSha1。
|
||||
本模块无同名定义(纯 from-import/外部 stub)时回落原语义,不改变 CExport/
|
||||
方法拒绝/装饰器分支行为。
|
||||
|
||||
附带同批入库:list 内置方法内联分派与裸名模块表匹配等本会话修复。
|
||||
Reference in new issue
Block a user