fix(gen): 模块限定构造按模块名解析 SHA1,修复 ctor 归属内核同名类
gfx.Scene3D(...) 的模块限定构造路径(Name 模块基)误用 trans.ModuleSha1
(当前文件 sha1,类在 gfx 模块)→ find_struct_by_module 落空 → 裸名回退
find_struct("Scene3D") 命中跨模块同名类中先注册的 entry(VKernel gfx 与
App gfx 都定义 Scene3D,0ae 先经 includes 预注册)→ ctor 生成
@0ae.Scene3D.__before_init__ → 链接 undefined symbol(Scene3D 根因)。
改为按模块名 _lookup_module_sha1("gfx") 精确解析 SHA1 后
find_struct_by_module 命中 App 版(9aab),与注解解析路径一致。
This commit is contained in:
1 parent
9b56d1d75c
commit
0a28df0864
1 file changed
+68
-17
@@ -85,14 +85,6 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
can: t.CSizeT = 0
|
||||
if cargs is not None:
|
||||
can = len(cargs)
|
||||
# [DET] len() 结果核对(SlotsBugTest/StringIterTest can 垃圾高位定位:
|
||||
# can=0x229_0000_0000=[cargs高32][count低32],怀疑 len() 生成代码 4 字节
|
||||
# 错位。门控:真实 count 远小于 2^32,can>=2^32 即异常,打印定位)。
|
||||
if (t.CUInt64T(can) & (t.CUInt64T(1) << 32)) != 0:
|
||||
lh_l: t.CUInt64T | t.CPtr = (t.CUInt64T | t.CPtr)(t.CVoid(cargs, t.CPtr))
|
||||
stdio.printf("[DET] len结果异常: can=%llu cargs=%llu data=%llu count=%llu cap=%llu\n",
|
||||
t.CUInt64T(can), t.CUInt64T(cargs), lh_l[0], lh_l[1], lh_l[2])
|
||||
|
||||
# super()/ctraits 检测:void 方法(如 __init__)命中后 build_call 返回
|
||||
# None 属预期(void call 无 SSA 值),必须用 hit_box 区分"命中已处理"
|
||||
# 与"未命中",否则 None 被误判继续主路径 → 内层 Call(super) 当裸名
|
||||
@@ -248,8 +240,18 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value)
|
||||
imp_ok: int = self.Gen.ImportsGen.is_module_imported(trans._imported_modules, mod_nm_qc.id)
|
||||
if imp_ok != 0:
|
||||
if trans is not None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1)
|
||||
# 模块限定构造 Module.Class(...):按模块名解析 SHA1 精确命中类。
|
||||
# 不能用 trans.ModuleSha1(那是当前文件 sha1,类在 gfx 模块)——
|
||||
# find_struct_by_module 落空后裸名回退 find_struct 会命中跨模块
|
||||
# 同名类中先注册的 entry(VKernel gfx 与 App gfx 都定义 Scene3D,
|
||||
# 0ae 先注册 → ctor 生成 @0ae.Scene3D.__before_init__ → 链接
|
||||
# undefined symbol,Scene3D 根因)。
|
||||
mod_sha1_qc2: str = None
|
||||
if mod_nm_qc.id is not None:
|
||||
mod_sha1_qc2 = self._lookup_module_sha1(mod_nm_qc.id)
|
||||
if mod_sha1_qc2 is not None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(
|
||||
func_name, mod_sha1_qc2)
|
||||
if gen_ctor_entry is None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct(func_name)
|
||||
if gen_ctor_entry is not None:
|
||||
@@ -347,12 +349,6 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
return self.Gen.CallGenCtor._translate_struct_ctor_kw(
|
||||
pool, builder, mod, struct_ty, func_name, cargs, can,
|
||||
keywords, kw_count, trans)
|
||||
# 仅位置参数:按字段顺序构建
|
||||
# [DET] 调用前 can 核对(与 len结果/callee 收到的 can 三级对照,
|
||||
# 定位 4 字节错位发生在 len 计算/调用传参/callee 读取哪一级)
|
||||
if (t.CUInt64T(can) & (t.CUInt64T(1) << 32)) != 0:
|
||||
stdio.printf("[DET] 调用前 can=%llu cargs=%llu\n",
|
||||
t.CUInt64T(can), t.CUInt64T(cargs))
|
||||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||||
pool, builder, mod, struct_ty, func_name, cargs, can, trans)
|
||||
|
||||
@@ -607,6 +603,16 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if self.Gen.ImportsGen.is_module_imported(
|
||||
trans._imported_modules, xm_mod_path) != 0:
|
||||
mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path)
|
||||
if mod_sha1_chk is None and trans._from_imports is not None:
|
||||
# import X as Y(如 import fat32_diskio as diskio):
|
||||
# 精确查不到别名,必须按别名还原后再查(精确→后缀→
|
||||
# LookupModNameByAlias 三级)。否则本校验被跳过 →
|
||||
# find_func_in_module 后缀匹配误命中本模块同名函数
|
||||
# (diskio.read 命中 fat32 自身 read)→ call 到错误
|
||||
# 符号 + 参数错位 + define 被 4 参调用污染(VKernel
|
||||
# llc "instruction expected to be numbered" 根因)。
|
||||
mod_sha1_chk = self.Gen.StructGen._resolve_module_sha1(
|
||||
xm_mod_path, trans._from_imports)
|
||||
if mod_sha1_chk is not None:
|
||||
ff_nm2: str = llvmlite.function_get_name(found_func)
|
||||
if ff_nm2 is not None:
|
||||
@@ -652,12 +658,19 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if bi_sha1 is not None:
|
||||
bi_ret: llvmlite.LLVMType | t.CPtr = None
|
||||
bi_p1: llvmlite.LLVMType | t.CPtr = None
|
||||
bi_p2: llvmlite.LLVMType | t.CPtr = None
|
||||
if string.strcmp(func_name, "ord") == 0:
|
||||
bi_ret = llvmlite.Int32(pool)
|
||||
bi_p1 = llvmlite.Int8(pool)
|
||||
elif string.strcmp(func_name, "chr") == 0:
|
||||
bi_ret = llvmlite.Int8(pool)
|
||||
bi_p1 = llvmlite.Int32(pool)
|
||||
elif string.strcmp(func_name, "min") == 0 or string.strcmp(func_name, "max") == 0:
|
||||
# min/max 数值比较(builtins.vp 定义 double 参数/返回,
|
||||
# int/float 实参经 coerce 提升;两参数)
|
||||
bi_ret = llvmlite.Double(pool)
|
||||
bi_p1 = llvmlite.Double(pool)
|
||||
bi_p2 = llvmlite.Double(pool)
|
||||
if bi_ret is not None:
|
||||
bi_sym: str = func_name
|
||||
if self.Gen.CallGenBase.is_cexport_func(bi_sha1, func_name) == 0:
|
||||
@@ -670,6 +683,8 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
pool, mod, bi_sym, bi_ret)
|
||||
if bi_decl is not None:
|
||||
llvmlite.add_param(pool, bi_decl, bi_p1, "v")
|
||||
if bi_p2 is not None:
|
||||
llvmlite.add_param(pool, bi_decl, bi_p2, "w")
|
||||
found_func = bi_decl
|
||||
# 使用访问器绕过 stub 类型限制
|
||||
found_ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
@@ -720,7 +735,25 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if found_func is None:
|
||||
fp_alloca: llvmlite.Value | t.CPtr = None
|
||||
if cl.func is None or cl.func.kind() == ast.ASTKind.Name:
|
||||
fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name)
|
||||
# 闭包内调用捕获的闭包变量(如 _cmd_cd 调 _build_path):
|
||||
# 从 env 读闭包对象指针,不能 lookup_var 跨函数命中父函数
|
||||
# 闭包 alloca(SSA 错乱 → llc "instruction expected to be
|
||||
# numbered",Terminal _cmd_cd 根因)。
|
||||
if trans is not None and HT.is_nonlocal_name(trans, func_name) != 0:
|
||||
fp_alloca = self.Gen.StmtGenDecl.load_nonlocal_var(trans, func_name)
|
||||
if fp_alloca is not None:
|
||||
# translate_closure_call 期望 i8** 存储(load 一次得闭包
|
||||
# 对象指针);load_nonlocal_var 已返回对象指针 → 临时
|
||||
# alloca 暂存
|
||||
i8_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_nl)
|
||||
tmp_alloca_nl: llvmlite.Value | t.CPtr = llvmlite.build_alloca(
|
||||
builder, i8_ptr_ty_nl)
|
||||
if tmp_alloca_nl is not None:
|
||||
llvmlite.build_store(builder, fp_alloca, tmp_alloca_nl)
|
||||
fp_alloca = tmp_alloca_nl
|
||||
else:
|
||||
fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name)
|
||||
if fp_alloca is not None:
|
||||
# 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用
|
||||
if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0:
|
||||
@@ -962,6 +995,24 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
found_name: str = llvmlite.function_get_name(found_func)
|
||||
if found_name is not None:
|
||||
call_name = found_name
|
||||
# CExport 裸名兜底:跨模块 stub declare 可能带 SHA1 前缀
|
||||
# (@"1fdad1c76fb116bc.malloc"),但定义端 CExport 函数
|
||||
# (mm.vp malloc/free/malloc_direct,返回注解含 t.CExport)
|
||||
# 用裸名 @malloc → 链接 undefined symbol: 1fdad1c76fb116bc.malloc。
|
||||
# found_func 非 None 时下方 is_cexport_func 裸名分支不执行
|
||||
# (该分支仅 found_func None 的模块限定路径),这里对带前缀
|
||||
# 的 declare 提取 sha1 再查 CExport 注册表,命中则改用裸名。
|
||||
if found_func.IsDeclared != 0:
|
||||
dot_pos_cx: str = string.strchr(found_name, 46)
|
||||
if dot_pos_cx is not None:
|
||||
cx_pre_len: t.CSizeT = string.strlen(found_name) - string.strlen(dot_pos_cx)
|
||||
if cx_pre_len == 16:
|
||||
cx_sha1_buf: str = pool.alloc(17)
|
||||
if cx_sha1_buf is not None:
|
||||
string.memcpy(cx_sha1_buf, found_name, 16)
|
||||
cx_sha1_buf[16] = '\0'
|
||||
if self.Gen.CallGenBase.is_cexport_func(cx_sha1_buf, func_name) != 0:
|
||||
call_name = func_name
|
||||
else:
|
||||
# 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用
|
||||
# 如 string.strchr(...) → @{sha1_of_string}.strchr
|
||||
|
||||
Reference in new issue
Block a user