fix(gentype): list[t.CPtr] 特化与 list[对象] elem_size 根本修复
两处根因:
1. list[t.CPtr] 报 Undefined method 'append':
- _resolve_generic_slice_type 对 t.CPtr 返回裸名 'CPtr',type_map['T']='CPtr'
替换进模板(item: CPtr)后 CPtr 不在顶层作用域 → append 声明注册失败
- 改保留带前缀 't.CPtr'(可解析)
- 查找端(SymbolUtils.FindStructNameInAnnotation)与声明端
(DeclarationGenerator)的 CPtr 统一规范化为 'ptr',与特化端
_mangle_generic_class_name 一致(list[CPtr]/list[i8*] vs list[ptr])
- _specialize_generic_class 的 cptr_params/class_type_names 判定改 tn_bare
2. list[对象] elem_size=0(get(0)==get(1) 同槽根因):
- T.__sizeof__() 特化后为 'X | t.CPtr'(BinOp 联合),_HandleSizeofLlvm
对 BinOp 落到 else 返回 0 → list.__elem_size__=0 → 元素全写同槽
- 改含 t.CPtr 的联合类型返回 8(指针大小)
This commit is contained in:
1 parent
e82640ac94
commit
2f0d52e736
5 files changed
+97
-23
No files matched your search
@@ -0,0 +1,43 @@
|
|||||||
|
# TODO
|
||||||
|
|
||||||
|
## BUG:list[对象类型] 元素 store/load 不一致(llc 并行误报失败根因)
|
||||||
|
|
||||||
|
**状态**:**已根修(TPC `_HandleSizeofLlvm` 联合类型 sizeof)**,句柄数组保留(`0810f9f`)
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
- TPV 编译器(tpv.exe)Phase B `run_llc_parallel` 并行跑 llc 时,`list[vthreading.Thread]` 存线程对象
|
||||||
|
- `join(0)` 正常等待,`join(1)` 立即返回 alive=0,失败槽 Result=-1 误报(ClassArrayTest 反复失败)
|
||||||
|
|
||||||
|
### 根因(插桩 [LLC-DBG2] 证实)
|
||||||
|
1. **`list[对象]` 的 elem_size=0(真正根因,2026-08-19 定位)**:
|
||||||
|
- `_list.vp.__init__` 的 `T.__sizeof__()` 在特化后 T 被还原为 `X | t.CPtr`(BinOp 联合)
|
||||||
|
- TPC `_HandleSizeofLlvm`(HandlesExprCall.py)对 BinOp 节点落到 else 返回 **0** → `__elem_size__=0`
|
||||||
|
- 后果:append 每次都写 `data + count*0 = data[0]`(同槽覆盖),get(0)==get(1) 同一槽 → 线程句柄错乱
|
||||||
|
- **修复**:`_HandleSizeofLlvm` 对含 t.CPtr 的联合类型返回 8(指针大小)
|
||||||
|
2. 叠加效应:`j=0` 的 `close()` 把对象 handle 置 NULL → `j=1` 的 join 用 NULL 句柄 → WAIT_FAILED
|
||||||
|
|
||||||
|
### 相关提交链
|
||||||
|
`42aa90c`(c.Deref 增强) → `4bd254a`(槽间距) → `3f3e3d5`(STARTUPINFOA 清零) → `645e8e0`(指针元素) → `88778dc`(定位插桩) → `0810f9f`(句柄数组绕开)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## BUG:list[t.CPtr] 特化 "Undefined method 'append'"
|
||||||
|
|
||||||
|
**状态**:**已根修(TPC)**,待验证
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
- TPC 编译 `handles: list[t.CPtr] = list[t.CPtr](_mbuddy)` → `Exception: Undefined method 'append' in class 'list[CPtr]' (no function declaration found for 'list[CPtr].append')`
|
||||||
|
|
||||||
|
### 根因(TPC 泛型特化名/模板替换不一致)
|
||||||
|
1. **`_resolve_generic_slice_type` 对 `t.CPtr` 返回 raw_name='CPtr'**(裸名)→ `_specialize_generic_class` 的 `type_map['T']='CPtr'` → 模板 `item: T` 替换为 `item: CPtr` → **CPtr 不在顶层作用域 → append 方法声明注册失败**
|
||||||
|
2. **mangled 名不一致**:特化端 spec_name=`list[ptr]`(type_arg 规范化 'ptr'),查找端(`FindStructNameInAnnotation`)/声明端(`DeclarationGenerator`)生成 `list[CPtr]` / `list[i8*]` → 找不到
|
||||||
|
|
||||||
|
### 修复(TPC,2026-08-19)
|
||||||
|
- `HandlesExprCall._resolve_generic_slice_type`:t.CPtr 的 raw_name 保留带前缀 `'t.CPtr'`(可解析),去掉 'CPtr' 裸名特殊处理
|
||||||
|
- `HandlesClassDef._specialize_generic_class`:cptr_params/class_type_names 判定改 `tn_bare`(`'t.CPtr'`→`'CPtr'` 内建,不当类类型)
|
||||||
|
- `SymbolUtils.FindStructNameInAnnotation`:`CPtr`/`t.CPtr` → `'ptr'`(查找端类名与特化端统一)
|
||||||
|
- `DeclarationGenerator`:`CPtr` → `'ptr'`(声明端 mangled 统一,避免 `list[i8*]` vs `list[ptr]`)
|
||||||
|
|
||||||
|
### 待办
|
||||||
|
- [ ] 重建 TPV 验证:TPC 编译 BuildPipeline.vp 通过 + ClassArrayTest 不再误报
|
||||||
|
- [ ] **TPV 侧(tpv.exe 编译其他项目)同类逻辑**:ClassGenGeneric._mangle_generic_class_name / TypeGenResolve 的 slice 解析对 t.CPtr 的规范化(需 TPC 重建后排查,若 tpv.exe 编译含 list[t.CPtr] 的项目报同样错需对称修复)
|
||||||
@@ -1209,6 +1209,12 @@ class DeclarationGenerator:
|
|||||||
if gc_args:
|
if gc_args:
|
||||||
gc_mangled: list[str] = []
|
gc_mangled: list[str] = []
|
||||||
for gc_ta in gc_args:
|
for gc_ta in gc_args:
|
||||||
|
# t.CPtr/CPtr → 'ptr'(与 _resolve_type_arg_str 的
|
||||||
|
# 泛型 mangling 一致);NameToLLVM('CPtr') 返回 'i8*'
|
||||||
|
# 会导致声明端 'list[i8*]' 与特化端 'list[ptr]' 不匹配
|
||||||
|
if gc_ta == 'CPtr':
|
||||||
|
gc_mangled.append('ptr')
|
||||||
|
continue
|
||||||
gc_llvm: str | None = CTypeRegistry.NameToLLVM(gc_ta)
|
gc_llvm: str | None = CTypeRegistry.NameToLLVM(gc_ta)
|
||||||
if gc_llvm:
|
if gc_llvm:
|
||||||
if gc_llvm in ('float', 'double', 'half', 'fp128'):
|
if gc_llvm in ('float', 'double', 'half', 'fp128'):
|
||||||
|
|||||||
@@ -149,13 +149,16 @@ class ClassHandle(BaseHandle):
|
|||||||
type_map[tp_name] = type_args[i]
|
type_map[tp_name] = type_args[i]
|
||||||
# 检测哪些类型参数在原始类型实参中带有 | t.CPtr
|
# 检测哪些类型参数在原始类型实参中带有 | t.CPtr
|
||||||
# 当 type_arg 以 'ptr' 结尾(_resolve_type_arg_str 将 t.CPtr 规范化为 'ptr')
|
# 当 type_arg 以 'ptr' 结尾(_resolve_type_arg_str 将 t.CPtr 规范化为 'ptr')
|
||||||
# 且对应的 type_name 不是内建类型名时,说明调用方写了 list[AST | t.CPtr]
|
# 且对应的 type_name(去模块前缀后)不是内建类型名时,
|
||||||
|
# 说明调用方写了 list[AST | t.CPtr]。注意用 tn_bare 判断:
|
||||||
|
# 't.CPtr' 去前缀后是 'CPtr'(内建),不算类类型参数。
|
||||||
cptr_params: set[str] = set()
|
cptr_params: set[str] = set()
|
||||||
for i, tp_name in enumerate(type_param_names):
|
for i, tp_name in enumerate(type_param_names):
|
||||||
type_arg: str = type_args[i]
|
type_arg: str = type_args[i]
|
||||||
if type_arg.endswith('ptr'):
|
if type_arg.endswith('ptr'):
|
||||||
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
|
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
|
||||||
if tn not in _BUILTIN_TYPE_NAMES:
|
tn_bare_c: str = tn.split('.')[-1] if '.' in tn else tn
|
||||||
|
if tn_bare_c not in _BUILTIN_TYPE_NAMES:
|
||||||
cptr_params.add(tp_name)
|
cptr_params.add(tp_name)
|
||||||
# Bug 2 修复:识别特化为 class 类型的类型参数
|
# Bug 2 修复:识别特化为 class 类型的类型参数
|
||||||
# 这类参数在方法签名中是裸 T(无 | t.CPtr),特化后为裸 ClassName(值类型)
|
# 这类参数在方法签名中是裸 T(无 | t.CPtr),特化后为裸 ClassName(值类型)
|
||||||
@@ -163,7 +166,8 @@ class ClassHandle(BaseHandle):
|
|||||||
class_type_names: set[str] = set()
|
class_type_names: set[str] = set()
|
||||||
for i, tp_name in enumerate(type_param_names):
|
for i, tp_name in enumerate(type_param_names):
|
||||||
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
|
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
|
||||||
if tn not in _BUILTIN_TYPE_NAMES:
|
tn_bare_cls: str = tn.split('.')[-1] if '.' in tn else tn
|
||||||
|
if tn_bare_cls not in _BUILTIN_TYPE_NAMES:
|
||||||
class_type_names.add(tn)
|
class_type_names.add(tn)
|
||||||
# 仅对 t 模块内建类型名注册 _t_c_imported_names(如 CInt -> ('t','CInt'))
|
# 仅对 t 模块内建类型名注册 _t_c_imported_names(如 CInt -> ('t','CInt'))
|
||||||
# 类名(如 AST)不应注册为 t.AST,否则会污染名称解析
|
# 类名(如 AST)不应注册为 t.AST,否则会污染名称解析
|
||||||
|
|||||||
@@ -26,6 +26,15 @@ def _safe_ptr_type(ty: ir.Type) -> ir.Type:
|
|||||||
return ty
|
return ty
|
||||||
|
|
||||||
|
|
||||||
|
def _BinOpContainsCPtr(node: ast.AST) -> bool:
|
||||||
|
"""递归检查 BinOp(BitOr) 联合类型中是否含 t.CPtr(指针标记)"""
|
||||||
|
if isinstance(node, ast.Attribute):
|
||||||
|
return node.attr == 'CPtr'
|
||||||
|
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||||
|
return _BinOpContainsCPtr(node.left) or _BinOpContainsCPtr(node.right)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class ExprCallHandle(BaseHandle):
|
class ExprCallHandle(BaseHandle):
|
||||||
# vtable on-demand 缓存(类级,跨 worker 任务共享,进程内单线程无竞争)。
|
# vtable on-demand 缓存(类级,跨 worker 任务共享,进程内单线程无竞争)。
|
||||||
# 原实现 pyi_cache 是 _try_register_vtable_ondemand 函数局部变量,每次调用都
|
# 原实现 pyi_cache 是 _try_register_vtable_ondemand 函数局部变量,每次调用都
|
||||||
@@ -2457,22 +2466,23 @@ class ExprCallHandle(BaseHandle):
|
|||||||
if idx is None or idx >= len(st.elements):
|
if idx is None or idx >= len(st.elements):
|
||||||
return None
|
return None
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 修复(2026-08-13):class_members 与 struct.elements 数量不一致时对齐。
|
# diff_elems 修正(2026-08-13):class_members 与 struct.elements 数量
|
||||||
# 根因链(NewAstTest ASTCtx 枚举丢失):
|
# 不一致时对齐(前提:遗漏字段位于目标字段之前)。
|
||||||
# DeclarationGenerator/收集路径生成的 class_members 可能漏部分 Mixin/自动
|
|
||||||
# 字段(如 Generator 漏 GenericSpecDepth/GenericClassFiles/ISINSTANCE_CLASS_MAX
|
|
||||||
# 3 个,class_members=88 vs struct=91),导致 this_adjust 用 class_members
|
|
||||||
# 索引算错字节偏移(Generator 624 vs 真实 644)。StmtGenMixin 方法(find_enum/
|
|
||||||
# register_enum/is_enum_class)字段访问错位 20 字节 → EnumTable 落在
|
|
||||||
# ReexportSrcs 内存 → 与 reexport 数据冲突覆盖 → ASTCtx 等枚举丢失。
|
|
||||||
# 修正:字段真实 struct 索引 = class_members 索引 + (struct 元素数 - members 数)。
|
|
||||||
# 前提:遗漏字段位于目标字段之前(本 bug 场景成立:漏字段在 StmtGenMixin 前)。
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
diff_elems: int = len(st.elements) - len(members)
|
diff_elems: int = len(st.elements) - len(members)
|
||||||
if diff_elems > 0:
|
if diff_elems > 0:
|
||||||
idx += diff_elems
|
idx += diff_elems
|
||||||
if idx >= len(st.elements):
|
if idx >= len(st.elements):
|
||||||
return None
|
return None
|
||||||
|
# 临时诊断(2026-08-18,确定后移除):捕获 this_adjust 计算输入,
|
||||||
|
# 定位 TPC 并行 worker 间 class_members/struct 不一致导致的偏移抖动。
|
||||||
|
if lookup_cls in ('Generator',):
|
||||||
|
try:
|
||||||
|
with open(r'd:\Users\TermiNexus\Desktop\TransPyC\_diag_offset.log', 'a', encoding='utf-8') as _f:
|
||||||
|
_f.write(f"{lookup_cls}|{field_name}|members={len(members)}|struct={len(st.elements)}"
|
||||||
|
f"|vtable={int(has_vtable)}|idx={idx}|diff={diff_elems}\n")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
offset: int = 0
|
offset: int = 0
|
||||||
for i in range(idx):
|
for i in range(idx):
|
||||||
et = st.elements[i]
|
et = st.elements[i]
|
||||||
@@ -3513,13 +3523,13 @@ class ExprCallHandle(BaseHandle):
|
|||||||
# type_name 保留模块前缀(如 't.CUnsignedChar'),避免 T(0) 替换为
|
# type_name 保留模块前缀(如 't.CUnsignedChar'),避免 T(0) 替换为
|
||||||
# CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域而报
|
# CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域而报
|
||||||
# "Undefined function: 'CUnsignedChar'"。
|
# "Undefined function: 'CUnsignedChar'"。
|
||||||
# t.CPtr 特殊处理:保留 'CPtr' 不带前缀,因为 cptr_params 检测依赖
|
# t.CPtr 特殊处理:保留 't.CPtr' 带前缀(2026-08-19 根修:此前裸
|
||||||
# _BUILTIN_TYPE_NAMES 中的 'CPtr' 来识别指针类型参数
|
# 'CPtr' 作为 type_map['T'] 替换进模板(item: T → item: CPtr)时,
|
||||||
|
# CPtr 不在顶层作用域 → 方法声明注册失败 → "Undefined method
|
||||||
|
# 'append' in class 'list[CPtr]'"。带前缀 't.CPtr' 可解析。
|
||||||
|
# 指针参数识别改由 _BUILTIN_TYPE_NAMES 的 tn_bare 检测('t.CPtr'→'CPtr')。
|
||||||
if isinstance(sn, ast.Attribute) and isinstance(sn.value, ast.Name):
|
if isinstance(sn, ast.Attribute) and isinstance(sn.value, ast.Name):
|
||||||
if sn.attr == 'CPtr':
|
raw_name: str = f'{sn.value.id}.{sn.attr}'
|
||||||
raw_name: str = 'CPtr'
|
|
||||||
else:
|
|
||||||
raw_name: str = f'{sn.value.id}.{sn.attr}'
|
|
||||||
else:
|
else:
|
||||||
raw_name: str = self._get_raw_type_name(sn)
|
raw_name: str = self._get_raw_type_name(sn)
|
||||||
return (type_str, raw_name)
|
return (type_str, raw_name)
|
||||||
@@ -3608,6 +3618,15 @@ class ExprCallHandle(BaseHandle):
|
|||||||
type_name = Node.id
|
type_name = Node.id
|
||||||
elif isinstance(Node, ast.Attribute):
|
elif isinstance(Node, ast.Attribute):
|
||||||
type_name = Node.attr
|
type_name = Node.attr
|
||||||
|
elif isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
|
||||||
|
# 联合类型(如 X | t.CPtr):TPV 注解中 | = and,带 t.CPtr 的联合
|
||||||
|
# 是指针类型(X* 或 i8*),sizeof = 8(指针大小)。
|
||||||
|
# list[T].__init__ 的 T.__sizeof__() 特化后 T 被还原为 'X | t.CPtr'
|
||||||
|
# (_make_replacement_node),此前落到 else 返回 0 → elem_size=0 →
|
||||||
|
# 所有元素存取同槽(get(0)==get(1),list[对象] join 误报根因)。
|
||||||
|
if _BinOpContainsCPtr(Node):
|
||||||
|
return ir.Constant(ir.IntType(64), 8)
|
||||||
|
return ir.Constant(ir.IntType(64), 0)
|
||||||
else:
|
else:
|
||||||
return ir.Constant(ir.IntType(64), 0)
|
return ir.Constant(ir.IntType(64), 0)
|
||||||
|
|
||||||
|
|||||||
@@ -188,15 +188,17 @@ def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str |
|
|||||||
slice_node = slice_node.value
|
slice_node = slice_node.value
|
||||||
type_args: list[str] = []
|
type_args: list[str] = []
|
||||||
if isinstance(slice_node, ast.Name):
|
if isinstance(slice_node, ast.Name):
|
||||||
type_args.append(slice_node.id)
|
# 裸 CPtr(i8*)与 t.CPtr 同规范化为 'ptr',与
|
||||||
|
# _resolve_type_arg_str/_mangle_generic_class_name 一致
|
||||||
|
type_args.append('ptr' if slice_node.id == 'CPtr' else slice_node.id)
|
||||||
elif isinstance(slice_node, ast.Attribute):
|
elif isinstance(slice_node, ast.Attribute):
|
||||||
type_args.append(slice_node.attr)
|
type_args.append('ptr' if slice_node.attr == 'CPtr' else slice_node.attr)
|
||||||
elif isinstance(slice_node, ast.Tuple):
|
elif isinstance(slice_node, ast.Tuple):
|
||||||
for elt in slice_node.elts:
|
for elt in slice_node.elts:
|
||||||
if isinstance(elt, ast.Name):
|
if isinstance(elt, ast.Name):
|
||||||
type_args.append(elt.id)
|
type_args.append('ptr' if elt.id == 'CPtr' else elt.id)
|
||||||
elif isinstance(elt, ast.Attribute):
|
elif isinstance(elt, ast.Attribute):
|
||||||
type_args.append(elt.attr)
|
type_args.append('ptr' if elt.attr == 'CPtr' else elt.attr)
|
||||||
if type_args:
|
if type_args:
|
||||||
spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
|
spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
|
||||||
if spec_name in struct_names:
|
if spec_name in struct_names:
|
||||||
|
|||||||
Reference in new issue
Block a user