From c2b9a26c627c319999404ae6c8f8b421e87551f0 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 29 Aug 2026 17:27:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(tpv):=20vpi=20=E6=B3=A8=E5=85=A5=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E7=B1=BB=E5=9E=8B=E5=AE=9A=E4=B9=89=20+=20list=20elem?= =?UTF-8?q?=5Fsize=20+=20=E8=B7=AF=E5=BE=84=E4=BF=AE=E5=A4=8D=EF=BC=8C?= =?UTF-8?q?=E6=B8=85=E7=90=86=E4=B8=B4=E6=97=B6=E8=AF=8A=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - VpiReader: 值 struct 全局/数组元素/函数返回类型注册完整定义,修复 llc use of undefined type;vpi 注入类后补 add_field 字段表(LARGE_INTEGER.QuadPart 恒 0 根因) - TypeGenResolve: list[str](pool, elem_size) 语义修复(参数个数误当 elem_size,Mat4 崩溃根因);t/c 内置命名空间 Subscript 特判 - Config: _join_path 防双份路径 - GenApi: 新增 add_field 代理 - 移除 DBG-VK/PHASEADBG/GAP-DIAG/DBG-EMP 临时诊断 --- App/lib/Projectrans/Config.vp | 8 +++++ App/lib/Stub/StubGen/VpiReader.vp | 48 +++++++++++++++++++++++++ App/lib/core/Gen/Class/ClassGenDef.vp | 10 ------ App/lib/core/Gen/Expr/ExprGenAttr.vp | 12 ------- App/lib/core/Gen/GenApi.vp | 15 +++++++- App/lib/core/Gen/StructGenMixin.vp | 13 ------- App/lib/core/Gen/Type/TypeGenResolve.vp | 38 +++++++++++++++++--- 7 files changed, 103 insertions(+), 41 deletions(-) diff --git a/App/lib/Projectrans/Config.vp b/App/lib/Projectrans/Config.vp index 813b311..aee0274 100644 --- a/App/lib/Projectrans/Config.vp +++ b/App/lib/Projectrans/Config.vp @@ -245,6 +245,14 @@ def _join_path(rel: str, project_dir: str) -> str: # 绝对路径(以 / 或 \ 开头)保持不变 if rel[0] == '/' or rel[0] == '\\': return rel + # [FIX] 命令行 --build-dir 按进程 cwd 给出的路径(如 ./TransPyV/.tpv_build2) + # 已含 project_dir 前缀(./TransPyV)时不再拼接,避免双份路径 + # (./TransPyV/TransPyV/.tpv_build2)。边界取到目录分隔符或串尾。 + if project_dir is not None: + pdl: t.CSizeT = string.strlen(project_dir) + if pdl > 0 and string.strncmp(rel, project_dir, pdl) == 0: + if rel[pdl] == '/' or rel[pdl] == '\\' or rel[pdl] == '\0': + return rel rel_len: t.CSizeT = string.strlen(rel) dir_len: t.CSizeT = string.strlen(project_dir) diff --git a/App/lib/Stub/StubGen/VpiReader.vp b/App/lib/Stub/StubGen/VpiReader.vp index a002458..6bc5833 100644 --- a/App/lib/Stub/StubGen/VpiReader.vp +++ b/App/lib/Stub/StubGen/VpiReader.vp @@ -1695,10 +1695,51 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy | t.CPtr, pool, cls_name, struct_ty_c, src_sha1) if entry_c is None: return 0 + # [FIX] vpi 注入类时同步注册字段到 StructEntry 字段表(名字+类型)。 + # 仅设置 Ty(LLVMType 含字段)而字段表空(FieldCount=0)时,使用端 + # lookup_field / lookup_field_by_class 按名字查字段失败 → 属性访问走 + # _deps_pending → Phase 1 includes 翻译无重译 → 失败版本落盘恒 0 + # (fileio.vp File.size 的 li.QuadPart → ret i64 zeroinitializer → + # read_all=0 → 二代 Config 加载失败根因)。 + # add_field 内部按 StdlibAlloc 复制字段名到 perm_pool,跨 reset 存活。 + afi_c: int = 0 + for afi_c in range(field_count): + af_name_c: str = (str)(t.CVoid(field_names_buf[afi_c], t.CPtr)) + af_ty_c: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(field_types_buf[afi_c], t.CPtr)) + GenApi.add_field(pool, entry_c, af_name_c, af_ty_c) GenApi.add_visible_struct(pool, cls_name) return 1 +# ============================================================ +# _ensure_full_value_types - 跨模块"值类型"引用注册完整定义 +# +# opaque 不足以支撑 llc:值 struct global(@_per_cpu = global %per_cpu_data)、 +# [N x opaque] 数组(@gdt = global [7 x %gdt_entry])、值 struct 返回类型 +# (declare %Mat4 @Mat4_Identity())均报 "use of undefined type"(值类型大小 +# 需已知)。vpi 注入类已 add_field 含字段(完整 Ty),在注册表可查时注册完整 +# 定义。指针引用(Ptr(Struct))无需——_scan_type_for_cross_module_refs 的 Ptr +# 分支添加 opaque 即可。 +# ============================================================ +def _ensure_full_value_types(mod: llvmlite.LLVMModule | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + ty: llvmlite.LLVMType | t.CPtr) -> None: + """递归为值 struct / 数组元素 struct 注册完整定义(递归深度守卫)""" + if mod is None or pool is None or ty is None: + return + match ty: + case llvmlite.LLVMType.Struct(_, _, _): + full_se_h: GenTypes.StructEntry | t.CPtr = GenApi.find_struct_by_type(ty) + if full_se_h is not None and full_se_h.Ty is not None: + llvmlite.module_add_named_type(mod, pool, full_se_h.Ty) + case llvmlite.LLVMType.Array(aelem_h, _): + if aelem_h is not None: + _ensure_full_value_types(mod, pool, aelem_h) + case _: + pass + + # ============================================================ # _inject_global_variable_declare - 从 vpi AnnAssign 创建模块级全局变量 declare # @@ -1792,6 +1833,8 @@ def _inject_global_variable_declare(pool: memhub.MemBuddy | t.CPtr, # undefined type named 'sha1.gdt_entry'"(fpu/fat32 合并 IR 根因)。 # 对齐 TranslatorGenMixin 创建全局前的 module_ensure_opaque_for_type # (_scan_type_for_cross_module_refs 递归 Array/Struct/Ptr)。 + # 值类型(struct 值 / 数组元素 struct)注册完整定义(见 _ensure_full_value_types) + _ensure_full_value_types(mod, pool, gv_ty_v) llvmlite.module_ensure_opaque_for_type(mod, pool, gv_ty_v) gv_v: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name_m, gv_ty_v) if gv_v is None: @@ -1889,6 +1932,11 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr, if ret_ty is None: ret_ty = i32_ty + # 值 struct 返回类型(如 gfx.vp Mat4_Identity -> Mat4)需要完整定义: + # declare %Mat4 opaque → llc "use of undefined type"。注册完整定义。 + _ensure_full_value_types(mod, pool, ret_ty) + llvmlite.module_ensure_opaque_for_type(mod, pool, ret_ty) + # 创建 declare func: llvmlite.Function | t.CPtr = llvmlite.create_declare( pool, mod, mangled_name, ret_ty) diff --git a/App/lib/core/Gen/Class/ClassGenDef.vp b/App/lib/core/Gen/Class/ClassGenDef.vp index 4897487..4272a7a 100644 --- a/App/lib/core/Gen/Class/ClassGenDef.vp +++ b/App/lib/core/Gen/Class/ClassGenDef.vp @@ -5,7 +5,6 @@ import ast import llvmlite import memhub import string -import stdio import viperlib import lib.core.VLogger as VLogger import lib.core.Gen.Translator as HT @@ -87,7 +86,6 @@ class ClassGenDef(ClassGenBase.ClassGenBase): if existing is not None: if existing.FieldCount == 0 and trans._declare_only == 0: if self.Gen.ClassGenBase._class_body_has_field(cd) != 0: - VLogger.info(f"[DBG-EMP] class={class_name} FC=0 ty={t.CUInt64T(existing.Ty)} 类体有字段,中和重建", "DBG") if existing.Name is not None: existing.Name[0] = '\0' existing.Ty = None @@ -230,8 +228,6 @@ class ClassGenDef(ClassGenBase.ClassGenBase): # L422-426 / FuncGenMixin L482-483),不致命,本遍文件不写盘。 if trans is not None: trans._deps_pending = 1 - # [PHASEADBG] 临时诊断:父类未注册即 pending 的根因(用后移除) - stdio.printf("[PHASEADBG] 父类未注册: class=%s parent=%s\n", class_name, pname) return 0 pfc: int = parent_entry.FieldCount for pfi in range(pfc): @@ -366,12 +362,6 @@ class ClassGenDef(ClassGenBase.ClassGenBase): # 翻译: ,请检查依赖模块是否已编译/注册"),不静默掩盖。 if trans is not None: trans._deps_pending = 1 - # [PHASEADBG] 临时诊断:字段注解类型未解析即 pending 的根因(用后移除) - dbg_ak: t.CInt = -1 - if aa.annotation is not None: - dbg_ak = aa.annotation.kind() - stdio.printf("[PHASEADBG] 字段类型未解析: class=%s field=%s annot_kind=%d\n", - class_name, tgt.id, dbg_ak) return 0 # 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时 # 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底) diff --git a/App/lib/core/Gen/Expr/ExprGenAttr.vp b/App/lib/core/Gen/Expr/ExprGenAttr.vp index af3cbd9..500568d 100644 --- a/App/lib/core/Gen/Expr/ExprGenAttr.vp +++ b/App/lib/core/Gen/Expr/ExprGenAttr.vp @@ -807,18 +807,6 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): # 查找字段索引和类型 field_info: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field( struct_ty, at.attr) - # [GAP-DIAG] 定位 th.arg=arg 字段索引错(func/arg 都解析成 3)根因: - # 打印字段名/结构体类型名/查到的索引与实际字段名 - if field_info is not None \ - and (string.strcmp(at.attr, "arg") == 0 or string.strcmp(at.attr, "func") == 0): - dbg_gap: str = pool.alloc(200) - if dbg_gap is not None: - ty_nm_gap: str = self.Gen.StructGen._extract_struct_name(struct_ty) - if ty_nm_gap is None: - ty_nm_gap = "?" - viperlib.snprintf(dbg_gap, 200, "[GAP] attr=%s ty=%s idx=%d fe_name=%s\n", - at.attr, ty_nm_gap, field_info.Index, field_info.Name) - stdio.printf("%s", dbg_gap) # REnum 变体字段查找: lookup_field 失败时,尝试 REnum 别名 # REnum 结构体字段名是 _p1/_p2/...,但源码用变体字段名访问(如 ty.Pointee) if field_info is None: diff --git a/App/lib/core/Gen/GenApi.vp b/App/lib/core/Gen/GenApi.vp index f9a5f72..c5c4245 100644 --- a/App/lib/core/Gen/GenApi.vp +++ b/App/lib/core/Gen/GenApi.vp @@ -398,7 +398,20 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr, return None -# ---------------- register_struct_alias(委托 StructGenMixin.register_struct_alias) ---------------- +# ---------------- add_field(委托 StructGenMixin.add_field) ---------------- +def add_field(pool: memhub.MemBuddy | t.CPtr, + struct_entry: GenTypes.StructEntry | t.CPtr, + field_name: str, + field_ty: llvmlite.LLVMType | t.CPtr) -> int: + """委托到 gen.add_field(原 Handles 壳)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.StructGen.add_field(pool, struct_entry, field_name, field_ty) + return -1 + + +# ---------------- register_struct_alias(委托 StructGenMixin.register_struct_alias) ---------------- def register_struct_alias(pool: memhub.MemBuddy | t.CPtr, name: str, sha1: str, diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index 2ec1f16..bfda2d8 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -221,14 +221,6 @@ class StructGenMixin: entry.Ty = struct_ty entry.FieldCount = 0 - # [DBG-EMP] 临时诊断:定位空类注册来源(win32base SECURITY_ATTRIBUTES / - # win32file WIN32_FIND_DATAA FieldCount=0) - if name is not None and (string.strstr(name, "SECURITY_ATTRIBUTES") is not None - or string.strstr(name, "WIN32_FIND_DATAA") is not None): - sha1_s: str = "?" - if sha1 is not None: - sha1_s = sha1 - VLogger.info(f"[DBG-REG] {name} sha1={sha1_s} Ty={t.CUInt64T(struct_ty)}", "DBG") # 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry) # SHA1 同样按 StdlibAlloc 选分配源(跨 1a/1b 存活,防 strcmp 悬空) @@ -359,11 +351,6 @@ class StructGenMixin: return -1 idx: int = struct_entry.FieldCount - # [DBG-EMP] 临时诊断:定位空类字段添加(win32base SECURITY_ATTRIBUTES / - # win32file WIN32_FIND_DATAA FieldCount=0) - if struct_entry.Name is not None and (string.strstr(struct_entry.Name, "SECURITY_ATTRIBUTES") is not None - or string.strstr(struct_entry.Name, "WIN32_FIND_DATAA") is not None): - VLogger.info(f"[DBG-ADDF] {struct_entry.Name} field={field_name} idx={idx}", "DBG") fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(struct_entry, idx) if fe is None: return -1 diff --git a/App/lib/core/Gen/Type/TypeGenResolve.vp b/App/lib/core/Gen/Type/TypeGenResolve.vp index f383532..6c921e5 100644 --- a/App/lib/core/Gen/Type/TypeGenResolve.vp +++ b/App/lib/core/Gen/Type/TypeGenResolve.vp @@ -230,6 +230,21 @@ class TypeGenResolve(TypeGenBase.TypeGenBase): """ if type_name is None: return None + # [FIX] 类型名指针越界(垃圾指针,ViperOS Mat4.m 嵌套泛型崩溃现场 + # strlen 收到 0x12124AE128712850 > x64 用户空间上限 2^47;低 16 位 + # 0x2850 残留 pool 偏移 → pool 越界写/寄存器破坏)。解引用前 fail-fast + # 暴露根因(不静默 strlen 段错误)。 + if t.CUInt64T(type_name) > 0x00007FFFFFFFFFFF: + VLogger.error(f"_norm_type_arg_name 类型名指针越界 (ptr={t.CUInt64T(type_name)}),疑似 pool 越界写破坏类型名指针", "TypeGen") + stdlib.exit(1) + # [FIX] 泛型实参分割(L341 "float, 4" → " 4")第二个参数带前导空格, + # 空格开头的字符串作为类型名/查表 key 是脏数据(ViperOS Mat4.m 的 + # t.CArray[t.CArray[float, 4], 4] 崩溃现场:_norm_type_arg_name 收到 + # " 4")。跳过前导空格后再按规则规范化。 + while type_name[0] == ' ': + type_name += 1 + if type_name[0] == '\0': + return type_name # ---- 1. 顶层联合 "A|B"('|' 仅在括号外才分割)---- # 括号感知:list[A|B] 的 '|' 在 '[' 内不是顶层联合,应留给第 1.5 步 # 泛型 slice 递归处理;list[A]|t.CPtr 的 '|' 在括号外才是联合分割。 @@ -316,7 +331,14 @@ class TypeGenResolve(TypeGenBase.TypeGenBase): elif inner_buf_g[ci_g] == ',' and cur_dep_g == 0: arg_cnt_g += 1 ci_g += 1 - arg_list_g: list[str] | t.CPtr = list[str](pool, arg_cnt_g) + # [FIX] 第二参数是 elem_size(元素字节大小),不是参数个数! + # str 是 i8*(8 字节)。此前误传 arg_cnt_g(参数个数,如 Mat4 + # 的 2)→ __elem_size__=2 → append 只写指针低 2 字节(高 48 位 + # 残留)→ get 读回垃圾指针(低 16 位=pool 偏移、高 48 位=相邻 + # 数据)→ _norm_type_arg_name 递归 strlen 崩(ViperOS Mat4.m + # t.CArray[t.CArray[float, 4], 4] 崩溃根因:strlen 参数三次 + # 均为低 16 位 0x2850、高 48 位漂移)。 + arg_list_g: list[str] | t.CPtr = list[str](pool, 8) if arg_list_g is not None: arg_start_g: t.CSizeT = 0 cur_dep_g = 0 @@ -1092,7 +1114,9 @@ class TypeGenResolve(TypeGenBase.TypeGenBase): tp_elts = tp_tup.elts tp_count = len(tp_elts) else: - tp_single: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 1) + # [FIX] elem_size=8(ast.AST | t.CPtr 指针 8 字节),原传 1 → get 只读 + # 1 字节拼指针(高 56 位残留)→ tuple 元素解析垃圾 + tp_single: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8) if tp_single is not None: tp_single.append(sub.slice) tp_elts = tp_single @@ -1791,7 +1815,9 @@ class TypeGenResolve(TypeGenBase.TypeGenBase): # 函数指针类型: t.Callable[[A, B], Ret] → i8* # 与 TPV 函数传指针惯例一致(函数值 bitcast 为 i8* 存储,调用时按实参重建签名) if string.strcmp(arr_at.attr, "Callable") == 0: - if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: + # t/c 是内置命名空间(不编译、不入 imported_modules),无需显式导入检查 + if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 \ + and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: self.Gen.TypeGenErr.fatal_type_error(node, "t.Callable 模块未导入") return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 指针类型: t.CPtr[T] → Ptr(T)(指向 T 的指针,T 自身可含指针层级) @@ -1800,7 +1826,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase): # 此前缺失 → t.CUInt8T | t.CPtr[t.CPtr] 联合退化为左值 i8 → # c.Deref(out) 报"参数不是指针类型"(zdeflate.vp compress out 根因) if string.strcmp(arr_at.attr, "CPtr") == 0: - if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: + if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 \ + and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: self.Gen.TypeGenErr.fatal_type_error(node, "t.CPtr 模块未导入") inner_cptr_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type( pool, sub.slice, imported_modules, from_imports, trans, depth + 1) @@ -1817,7 +1844,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase): return llvmlite.Ptr(pool, inner_cptr_ty) if string.strcmp(arr_at.attr, "CArray") != 0: self.Gen.TypeGenErr.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)") - if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: + if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 \ + and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray 模块未导入") # 单参数形式: t.CArray[elem_ty] → Ptr(elem_ty) # 相当于 t.CArray[elem_ty, None],表示静态推导长度数组