TermiNexus
|
4fc067e3bf
|
perf(tpc): 按 profile 消掉两处主热点(stub 索引每 miss 重扫目录 / vtable 每类全扫函数)
依据 PROF/main_prof_10152.prof(main_time.txt: 失败 2362.46s,72 个文件全部走
顺序 _translate_file,tottime 合计 2288.9s):
tottime calls 函数
491.7s 723782 nt._path_isdir ← 总时长 21%
268.6s 15762 StructGen._generate_structs
182.9s 479819 nt.listdir ← 8%
87.2s 657640754 builtins.isinstance
78.6s 41514263 ntpath.join
75.9s 83047878 ntpath.splitroot
75.7s 1631 StructGen._create_Vtable_globals (46ms/次)
66.6s 238007 HandlesImports._build_stub_index
63.0s 317868145 str.startswith
38.4s 175751378 str.endswith
...
── 仅 isdir + listdir + join/splitroot/endswith ≈ 850s ≈ 总时长的 37%
一、_build_stub_index 的零 syscall 快路径(HandlesImports + Phase2Translator)
它由 _TryLoadStructFromStub 的**每次索引 miss** 调用(238k 次),每次都要
2× os.path.isdir + 2× os.listdir + 全量 endswith/join 重拼文件集合 ——
这正是上面 isdir 723k / listdir 479k 的主要来源。
改为:写入方显式置脏(ImportHandle.MarkStubSetDirty),未置脏时直接返回。
置脏点:① 每个文件翻译入口(_translate_file,顺序与 worker 模式皆按文件粒度
覆盖)② 写 temp/<sha1>.stub.ll 之后 ③ 注册 include 写 output/<sha1>.stub.ll
之后。索引建完即清脏。语义:增量重扫、output 覆盖 temp 全部不变,只是把
"集合是否变化"由目录扫描改为写入方免费告知(编译进程内 stub 只增不改)。
二、_create_Vtable_globals 的 O(类数 × 函数数) → O(函数数)
原实现对每个候选类都遍历一遍 self.functions 找 "{ClassName}." 前缀且非
declare 的函数;改为一次性预计算"非 declare 函数名的全部点分前缀"集合,
每类只做一次集合查询。判据等价(startswith(prefix) ⟺ prefix 在点分前缀集)。
重编后请再抓一次 profile 复核收益;下一梯队热点是 _generate_structs
(268.6s tottime / 35k 次调用)与 _parse_llvm_type(3.5M 次调用)。
|
2026-09-29 14:36:57 +08:00 |
|
TermiNexus
|
f1e7fd6c28
|
perf(tpc): _LookupStubFuncType 的目录计数按目录 mtime 缓存,去掉每次调用的全量 listdir
类别:纯提速(判定结果不变)。原实现每次调用都要
sum(1 for f in os.listdir(output_dir) if f.endswith('.stub.ll'))
sum(1 for f in os.listdir(temp_dir) if f.endswith('.stub.ll'))
只为构造一个"stub 是否新增"的签名;本函数位于每次跨模块函数/方法查找的热路径
(20 个调用点),开销 = O(目录文件数) × 调用次数,与编译工作量无关,工程越大越亏。
改为 ImportHandle._CountStubFilesInDir(DirPath):同一「目录 + 目录 mtime_ns」
只 listdir 一次,mtime 命中即复用上次计数(每目录一次 os.stat 代替一次
os.listdir + 全量 endswith 判定)。
判据:stub 目录只增不改、且由主进程在批次之间写入 ⇒ 只有目录条目增删才会改变
计数,而 Windows/NTFS 在条目增/删/改名时会更新目录 mtime。
取不到 stat(目录不存在/权限)时不写缓存、退化为每次实算。
计数仍是权威签名,缓存只决定"要不要重新 listdir",不改变任何判定结果
(增量重扫、output 覆盖 temp 的语义逐字不变)。
|
2026-09-29 14:32:39 +08:00 |
|
TermiNexus
|
f4c8c48748
|
fix(tpc): 函数声明创建全部收口到唯一幂等入口,消除 DuplicatedNameError 裸抛
类别 a(编译器缺陷)+ b(机制漏豁免)。报错:翻译 lib\core\Gen\Expr\ExprGenName.vp
失败,报文只有名字 dddc595175f00c66.ExprGenAttr.find_global_in_module
⇒ llvmlite DuplicatedNameError(NameScope.register 对 GlobalValue
deduplicate_name=False,同名 global 再建必抛,__str__ 只回名字)。
根因(已取证,非猜测):
- llvmlite Module 里 `scope`(NameScope,注册/去重)与 `globals`(OrderedDict)
是两套结构;`add_global` 只在构造时写入 ===> 「名字已在 scope._useset、
但 globals 查不到」这一状态一旦出现,任何"先查 globals 再建"的守卫都会失效。
- 该状态由**清理不完整**制造:删旧名时只删"对象真名 existing_func.name/old_name",
而字典键/目标名(func_name / MangledName)仍留在 scope._useset。
别名注册(Gen.functions[短名] = 名为全名的对象)恰好让二者不同名。
- 另有若干创建点只看 Gen.functions、完全不看 module.globals(裸建 ir.Function),
只要 module.globals 已有同名声明就裸抛 DuplicatedNameError。
本次收口(函数声明创建的唯一入口 = BaseGen._CreateOrReuseFuncDecl):
1. BaseGen._CreateOrReuseFuncDecl:新增"名字被非函数 global 占住"分支,把冲突
双方(类型 + repr)报出来,替代原 llvmlite 只给名字的裸抛。
2. 清理不完整处补全为「同时清 真名 + 目标名」:
- HandlesImports.py 模板 declare 装载(clearing func_name 之外还清 existing_func.name)
- HandlesFunctions._replace_function_decl(clearing {old_name, MangledName})
- 其 except 对 FailFastError 改为上抛(不再回退成复用旧声明)
3. 裸建 ir.Function 的创建点改走唯一入口(module.globals 同名则复用、
签名冲突/非函数冲突则 fail-fast):
- HandlesExprCall._HandleStaticMethodCallLlvm({sha1}.Class.Method) ← 本现场形态
- HandlesExprCall._HandleMethodCallLlvm 的 class_sha1 回退分支
- HandlesExprCall._try_declare_c_lib_func / HandlesExprBuiltin._try_declare_c_lib_func
- HandlesAssign 模块级全局赋值处的函数声明
- HandlesImports.__before_init__ 声明(原查 NewFuncName 却建 MangledName)
- HandlesFunctions._EmitFunctionLlvm(补登记 module.globals 已有声明,
使既有的签名修复路径生效,而不是裸建撞名)
行为等价性:上述各点原先"撞名"时必然抛 DuplicatedNameError(即必失败),
收口后要么复用同一符号、要么 fail-fast 报出两侧签名/冲突类型,无静默降级。
|
2026-09-29 13:50:44 +08:00 |
|
TermiNexus
|
8c831a38d3
|
fix(tpc): 局部 str*/str|t.CPtr 注解不再被压平成 i8*(补 PtrCount<=1 豁免)
类别 b(机制漏豁免):`TypeInfo.IsStr` 对**任何** CChar + 指针层都为真,
局部 AnnAssign 处却无条件把 PtrCount 压成 1,导致 `argv_arr: str*` 被声明为
i8*,而同名模块级全局 `_argv: str*` 走 HandlesAssign._EmitGlobalAnnAssignLlvm
的 FromNode 得到 i8**,于是 `_argv = argv_arr` 被
「指针隐式转换已禁止(层数不同):i8* → i8**」拦下(includes/sys.vp:114、
_init_argv_posix 同款 L148)。
同一规则在 HandlesFunctions.py:599 / 690 / 722 / 1434 / 1514 / 1602 / 1662 与
HandlesImports.py:1440 / 1542 都已带 `IsStr and PtrCount <= 1` 豁免(注释写明
"str | t.CPtr 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平"),
唯独 HandlesAnnAssign.py:452 漏了这一条 —— 本次补齐:只压平 PtrCount<=1,
`str*` / `str | t.CPtr` 保持 i8**;_str 影子结构与 var_ptr_element(8 字节步长)
标记仍照旧执行。
判据(不猜):
1. TPV 参考实现产物 Test/SysLibTest/.tpv_build/temp/0c/0cc16828640f94b7.ll:
`@"0cc16828640f94b7._argv" = global i8**`、_init_argv_win32 内
`alloca i8**`(argv_arr)、`store i8** %x, i8*** @"..._argv"` —— 局部与全局
同为 i8**。
2. TPC 全局侧 FromNode 对 `str*` 给出 PtrCount=2(CChar + str 的 1 层 + CPtr 的 1 层)。
重编即可验证 sys.vp 第 84/114 行一致。
|
2026-09-29 13:33:54 +08:00 |
|
TermiNexus
|
a6c9003a19
|
fix(tpc): struct body 解冻改用 llvmlite 公开属性 elements(原 _elements 是空操作)
类别:a 编译器缺陷(机制漏豁免:错误的"解冻"字段名使所有 body 重建路径失效)。
现场(连续多轮复现):TransPyV Generator.vp:200
`self.ExprGenFstr = SubExprGenFstr` 报「指针隐式转换已禁止(层数不同):
%"a7b68c79f39cb4d3.ExprGenFstr"* → i8**」,[成员槽来源] 显示
class_members[Generator] 下标 11 声明槽类型**正确**,而布局
'47382dc8277c9d28.Generator' 的 elements[11]=i8**。
取证(已核对全部产物与共享符号表,排除"来源侧退化"):
- TransPyV/output/*.stub.ll 与 temp/47382dc8277c9d28.stub.ll 里
%"47382dc8277c9d28.Generator" 的 slot11 全部是 %"a7b68c79f39cb4d3.ExprGenFstr"*,
**没有任何 stub 含 i8**;
- 共享符号表(temp/_shared_sym.json → symbol_table_bytes)里
Generator.Members['ExprGenFstr'] = CTypeInfo(BaseType=CStruct('ExprGenFstr'),
PtrCount=1, IsStruct=True),也**正确**。
真根因:llvmlite 本版本 IdentifiedStructType 的字段是**公开属性 `elements`**
(types.py: `self.elements = None`;`is_opaque` = `elements is None`;
`set_body` 仅在 `elements is not None` 时抛 "already defined")。而本仓所有
"清除 body 以便重建"的路径都写 `st._elements = None`(不存在的属性)⇒ **空操作** ⇒
⇒ `if struct_type.elements is None` 恒假 ⇒ set_body 永不执行 ⇒ 早期冻结的错误布局
(如 i8**)无法被任何后续权威重建覆盖:
· StructGen Step 4 逐元素校验已判定不一致(_slot_types_ok=False),清空失败 ⇒
既不能 skip 也不能重建 ⇒ 错布局被静默保留;
· HandlesClassDef 的本地定义权威重建点(class_members 已重建为正确类型后)
同样无法刷新 body。
两处叠加正是"class_members 正确、布局却是 i8**"的稳定现象,也解释了此前
TypeGenCDef(槽3) / ExprGenFstr(槽11) 在不同构建里交替出现(取决于谁先被冻结)。
修复:四处解冻改为写公开属性 `elements`:
· StructGen.py Step 4 前置校验失败后的清空;
· StructGen.py sha1 全名 key 的 struct 清空;
· StructGen.py T* 占位清空;
· HandlesClassDef.py @t.NoVTable 本地定义点的清空。
清空后 is_opaque 恢复为真 ⇒ _TryLoadStructFromStub(declare 侧权威 body)或
class_members 重建可真正 set_body。
|
2026-09-29 13:13:17 +08:00 |
|
TermiNexus
|
9d8aedec4a
|
fix(tpc): 函数声明创建收口到幂等入口 _CreateOrReuseFuncDecl;清理 DDEBUG 探针
类别:a 编译器缺陷(根因修复)+ 调试探针移除。
现场:翻译 CallGenFd.vp 时抛 llvmlite.ir._utils.DuplicatedNameError:
'5d84ea579d83ef73.CallGenFd._translate_fakeduck_call'(llvmlite 的
NameScope 按名字去重,GlobalValue.deduplicate_name=False ⇒ 同名 global
建第二次必抛,且报文只给名字、不给两侧签名)。
根因:BaseGen._get_or_declare_function 建完 ir.Function 后**只加入
module.globals**(llvmlite 自动)而**未登记 Gen.functions**;而
HandlesFunctions._EmitFunctionLlvm 的 need_new 判据只看 Gen.functions
(`MangledName not in Gen.functions`)⇒ 同一名字再建一次 → DuplicatedNameError;
该处 except 又把它吞掉(非 strict 模式只 LogWarning)→ 函数始终没进
Gen.functions → 后续其它创建点(FuncGen._get_or_declare_func /
get_or_declare_c_func,同样只查 self.functions)再建 → 异常从别处逃逸到
Phase2Translator。
修复:
1. BaseGen 新增 _CreateOrReuseFuncDecl(name, func_type) —— 函数声明创建的
唯一幂等入口:module.globals 已有同名函数且**函数类型结构串相同**则复用
(并补登记 Gen.functions;FunctionType 无 __eq__,只能比 str);
类型不同则 fail-fast 报出两侧签名(declare/define 分裂的真因),
绝不静默复用错签名(调用点会按错签名传参)。
2. _get_or_declare_function 改走该入口(顺带补登记 Gen.functions);
FuncGen._get_or_declare_func / get_or_declare_c_func 改走该入口;
HandlesFunctions 定义路径改走该入口,且该处 except 对 FailFastError
直接 re-raise(不再吞)。
3. 清理遗留调试探针(含 sys.exit(1)):BaseGen 三处 [DDEBUG]
(_get_or_declare_function 双点 / _mangle_func_name 前导点与结果双点)、
HandlesExprAsm 两处 [DDEBUG_ASM]、HandlesExprCall 一处
[DDEBUG] _HandleClosureCallLlvm。
|
2026-09-29 13:00:11 +08:00 |
|
TermiNexus
|
fd212b3ff8
|
fix(tpc): 联合强转 (T|t.CPtr)(x) 及其属性访问失败改为 fail-fast(附判定依据)
类别:b 机制漏豁免(把静默 return None 改成响亮失败并带证据)。
现场:TransPyV lib/core/Gen/Expr/ExprGenBase.vp:360 的
v = (ast.Expr*(node)).value 报“赋值表达式 'value'(Attribute 形态)编译期
求值为空”,而同一函数前三条 (ast.Assign/AnnAssign/AugAssign*(node)).value
同款写法正常 ⇒ 无法从报错看出是哪一步丢了类型。
两处静默返回改为 fail-fast(均只对该强转形态生效,其余路径行为不变):
1. HandlesExprCall._HandleTypeUnionCastLlvm:目标类型串解析失败(原为
_vlog().warning + return None)。新增 _DescribeUnionCastFailure 取证:
MergeTypes 返回值/ToString()/异常、_ExtractTypeStrFromUnionBinOp 结果,
以及联合中每个操作数在符号表与类登记表(Gen.structs / _struct_sha1_map /
class_sha1_map)的命中情况 —— 直接指认“基座类名没被当成类”还是
“CPtr 标记侧解析失败”。
2. HandlesExprAttr._handle_attr_call_result:(T|t.CPtr)(x).attr 的 5 个
return None(基座求值为空 / 非指针 / find_struct_by_pointee 未命中 /
结构体不透明 / 成员偏移取不到)改为 _FailFastAttrCallBase,报文含联合
基类名与三家登记表命中、被指类型 elements、class_members 项数与目标成员偏移。
原因:(T|t.CPtr)(x) 只可能来自指针强转(parser 把 (T*)x / (T*)(x) / T*(x)
统一产成该 Call),必须有值产出;静默丢弃会让整条表达式被判为空,把
“类名解析失败 / 结构体不透明 / 成员偏移取不到”三种不同根因混成同一条报文。
|
2026-09-29 12:23:54 +08:00 |
|
TermiNexus
|
7167703ca7
|
fix(tpc): 降级判据改用「注解形态 + 解析结果形状」,放在字段类型唯一漏斗
上一版拦截失效的原因(实测):`class_member_annotations` 全仓**只被声明与读取、从未被
写入**(Step 2 一直是空转),故依赖它的 `_HasDegradedMemberTypes` 恒为 False。改法:
1) SymbolUtils 新增两个**形状判据**(纯判定,不做类型解析):
- IsI8DoublePtrType(T):是否 i8 系两层指针(`i8**`)= `T | t.CPtr` 在 T 类型丢失后
退化成的形状;
- IsClassRefPtrAnnotation(Ann):注解是否「指针包装的类引用」(rawptr[Mod.Class] /
Mod.Class | t.CPtr;内层为非 t/c 模块的 Attribute 或首字母大写裸名)。
2) HandlesBase.CollectAnnAssignMember(字段类型的**唯一漏斗**,覆盖本地类 /
跨模块 .vpi / 嵌套类三条写入链)新增硬判据:注解是类引用指针 **且** 解析结果正是
`i8**` ⇒ 必属类型信息丢失,当场 fail-fast,并打出 CTypeInfo 全字段(BaseType/
PtrCount/IsStruct/IsTypedef/IsEnum/Name)与内层名的符号表条目标志。此前的
`_CheckPtrAnnotationKeepsClass` 只看"void 基座且无类身份",而现场这条链**带 Name/
IsTypedef**(Attribute 分支的 typedef 出口 → BaseType=CVoid 但 Name=类名),正好漏过。
3) StructGen 删除依赖那张空表的 `_HasDegradedMemberTypes` / `_IsI8DoublePtr` /
`_IsClassRefPtrAnnotation` 及 set_body 前的拦截(改由漏斗处兜住,不留死代码)。
现场:Generator.vp:200 `self.ExprGenFstr = SubExprGenFstr`
→ 布局槽 elements[11]=i8** 而声明 %"a7b68c79f39cb4d3.ExprGenFstr"*
|
2026-09-29 12:04:20 +08:00 |
|
TermiNexus
|
dab0823f5c
|
fix(tpc): 收紧「类身份」判据 + REnum 变体载荷解析失败不再被吞
承接 02d89b09:上一版判据"BaseType 是 CVoid ⇒ 类型信息丢失"**误伤 REnum** ——
REnum 类型条目本身 `BaseType=None`,`T | t.CPtr` 合并时 `_MergeAllComponentTypes`
末尾会把空 BaseType 默认填成 CVoid,但 IsRenum/IsStruct/Name 齐备,`_ctype_to_llvm`
仍能解析出 `%<sha1>.T*`。于是合法注解 `Pointee: rawptr[LLVMType]`(REnum 变体载荷)
被打成致命错误,异常又在此处被上层吞掉 ⇒ 变体只剩 __tag。
两处修正:
1) HandlesBase._CheckPtrAnnotationKeepsClass:判据收紧为「BaseType 是 CVoid **且
没有任何类身份**(IsStruct / IsRenum / IsEnum / Name 全空)」才失败。
2) HandlesImports REnum 变体载荷注册:历史上 `CollectAnnAssignMember` 的异常被上层
吞掉、`parsed` 为 None 时静默跳过 ⇒ class_members 只剩 __tag、变体循环中断
(现场同前缀 structs 键只有 LLVMType_Int / LLVMType_Ptr,源顺序其后还有
Func/Array/Struct/…),进而使变体构造丢载荷、match 捕获绑不上。现改为:
- 只把 AnnAssign 当载荷声明(pass / docstring 合法跳过,如 `class Void: pass`);
- 解析抛异常 ⇒ fail-fast 并带上原异常(拒绝留下只有 __tag 的成员表);
- 解析返回 None ⇒ 同样 fail-fast。
|
2026-09-29 11:24:57 +08:00 |
|
TermiNexus
|
53bde9157e
|
fix(tpc): REnum 变体嵌套结构体按需补发 + 模式捕获绑不上即 fail-fast
a 编译器缺陷:导入模块侧 stub 只声明主 REnum(`%"…LLVMType" = type {…}`),**不含**
变体嵌套结构体(`LLVMType_Ptr` 等)——它们由 `_EmitExternalClassDeclLlvm` 的 REnum
分支按主结构体布局就地生成。若本模块从未触发该 REnum 的外部声明发射:
1) match 模式捕获(`case llvmlite.LLVMType.Ptr(pointee_cs):`)绑定静默为空 ⇒ case
body 里引用的绑定名随后报"未定义名称"(现场 VpiReader.vp:1521 `pointee_cs`);
2) REnum 变体构造的载荷实参静默丢弃(只写 tag)—— 静默错码。
修法:
- 新增 BaseHandle._EnsureRenumVariantStruct:成员缺失时按需补发(先试 stub,再按
类 sha1 找到定义模块 .vpi 触发 `_TryLoadClassMembersFromPyi` → 内部即调
`_EmitExternalClassDeclLlvm`)。
- HandlesMatch._HandleRenumMatchLlvm:改用该助手;**模式捕获登记不全即 fail-fast**
(报出变体名、class_members 项数、structs 命中与同前缀键),绝不让绑定名留到
取名时才炸。
- HandlesMatch 非 REnum 兜底分支:MatchClass 含捕获时改为 fail-fast,并列出判据
(IsEnumMember/EnumName/IsRenum/IsStruct/IsEnum),直接暴露"外层 REnum 判定为何
未成立"。
- HandlesExprCall._HandleREnumConstructLlvm:载荷实参存在而嵌套结构体缺失时补齐,
补不上则 fail-fast(拒绝产出"只有 tag 没有载荷"的值)。
|
2026-09-29 11:21:19 +08:00 |
|
TermiNexus
|
02d89b0900
|
fix(tpc): 字段解析「内层是类却成通用指针」当场 fail-fast(降级源头定位)
承接 b8ed33a2 / 7fb0e498:前两者修的是**结果**(错位 body),本次收**源头** ——
class_members 在某个早期 pass 被解析出 i8**(void 基座 + 2 层),随后被冻进
struct body。CollectAnnAssignMember 是字段类型的唯一汇总点,在此加判据式 fail-fast:
判据(只拦"必属类型信息丢失"的组合):注解是指针包装(rawptr[T] / t.CPtr[T] /
裸名 CPtr[T] / `T | t.CPtr` 联合)且其**内层节点(Name/Attribute)的名字在
Gen.structs 或 Gen._struct_sha1_map 中有类定义**,而解析出的 BaseType 却是
t.CVoid ⇒ 必定是解析路径把类丢了,响亮失败并附完整判据:
解析结果 BaseType/PtrCount/IsStruct/IsTypedef/Name
符号表[内层名] => IsTypedef/BaseType/PtrCount/IsStruct/IsRenum/IsModuleAlias/IsEnumMember
Gen.structs 命中 / _struct_sha1_map 命中
放行:rawptr[rawptr] 这类本就 void 基座的多层指针、模块名、泛型特化实参(内层非
Name/Attribute)—— 不误伤合法写法。
|
2026-09-29 00:21:39 +08:00 |
|
TermiNexus
|
c49dc1d915
|
fix(tpc): 类型静默降级改 fail-fast + 成员槽写入失败附来源明细
a 编译器缺陷:类型信息缺失时静默兜底会掩盖上游根因,兜出来的"看着合理"的类型
(如 i8**)又会让下游报出与真因无关的错。按既定铁律改为响亮失败:
1) HandlesImports._parse_llvm_type:被指类型是具名聚合(%...)却在
create_structs=True 下取不到结构体时,原静默 `return PointerType(i8)` ——
结构体指针被悄悄变成通用指针,外层再套一层即成 i8**。改 fail-fast。
(create_structs=False 属"尚未加载",非异常,保持原样。)
2) HandlesTypeMerge._HandleSubscript:新增判据自洽守卫 —— base 是指针标记
(rawptr / t.CPtr / 裸名 CPtr / 别名)而 IsPtrSubscriptNode 未命中时,
历史上会落到 CollectAll 当"数组下标"解析、静默产出「基座 void + 多层指针」
(i8**)。现 fail-fast(判据分裂即内部不变量被破坏)。
3) HandlesAssign._HandleAttributeStoreLlvm(`self.字段 = 值`):成员槽写入失败
时追加「成员槽来源」明细 —— class_members 声明侧(项数/base/下标/声明槽类型)
+ 布局侧(struct IR 名/元素数/elements[offset])+ structs 键数与是否同一对象,
使"声明侧退化"与"布局侧退化"一眼可分,杜绝再靠猜。
现场:TransPyV/App/lib/core/Gen/Generator.vp:193 `self.ExprGenConst = SubExprGenConst`
→ 指针隐式转换已禁止(层数不同):不能把指针类型
%"cfd1f3d0d7e87fea.ExprGenConst"* 隐式转为 i8**
|
2026-09-28 23:59:29 +08:00 |
|
TermiNexus
|
78c5155de9
|
revert(tpc): 回滚 51de3b6d 的 [DIAG-decl] 临时诊断
「跨模块函数形参退化成 i32*」(constant_get_str_val / function_get_name 第 0 形参
i32*)一族已由 1c1f78e7 定位修复(同名枚举成员遮蔽类定义,判据按 IsEnumMember
区分),探针使命结束,整体移除:
- FuncGen._RecordDeclFrom / _DescribeI32ParamDiag 及两处调用点
- _adjust_args fail-fast 报文中的 _diag_extra 拼接
- BaseGen._get_or_declare_function 入口记录点
- HandlesBase.GetOrCreateFuncDecl 入口记录点
|
2026-09-28 23:23:02 +08:00 |
|
TermiNexus
|
833e8c7c33
|
fix(tpc): 识别点号写法的 REnum 变体构造 mod.REnumClass.Variant(...)
a 编译器缺陷(同一语义两种书写的判据不一致):HandlesExprCall 的跨模块 REnum 变体
构造分支只判 `isinstance(Node.func.value, ast.Name)`,即只认裸名写法
`LLVMType.Ptr(x)`;**点号写法** `llvmlite.LLVMType.Struct(fields, fcount, name)`
(Node.func.value 是 Attribute)漏掉,落到下方"模块函数 Struct"路径 ⇒
· 返回类型被当成普通函数返回值(实为 boxed 变体构造指针);
· 实参少一个 pool(arity 也不对)。
现场:ClassGenDef.vp:116 的 `*existing.Ty = llvmlite.LLVMType.Struct(...)`
报"不能把指针类型 %LLVMType* 隐式转为值类型 %LLVMType"。
补齐:新增同口径分支——Node.func.value 为 Attribute 时,按其 attr(REnum 类名)
在符号表(先试 f"{ModulePath}.{attr}" 再试裸名)取 IsRenum 条目,命中
RenumVariants 即走 _HandleREnumConstructLlvm(与裸名分支同一实现)。与
includes/llvmlite/__types.vp:195、__builder.vp:173 的既有用法一致。
|
2026-09-28 23:14:08 +08:00 |
|
TermiNexus
|
1c1f78e7b3
|
fix(tpc): 修正枚举判据——按 IsEnumMember 区分成员/类型(bb05a157 判反了)
a 编译器缺陷:bb05a157 用 `not Entry.IsEnum` 排除"枚举类型",但现场实测枚举
**成员**条目的标志组合是
IsEnum=True + IsEnumMember=True + BaseType=CEnum
(成员的 IsEnum 也被置真)⇒ 成员被误判成枚举类型,`rawptr[Constant]` 落 i32*,
`constant_get_str_val` 形参再次退化成 i32*。
正确判据(两处同源):
枚举**类型** = IsEnum and not IsEnumMember ⇒ 走枚举分支(宽度 i32 等)
枚举**成员**(IsEnumMember)⇒ 不是类型 ⇒ 让位给类定义("有类定义 ⇒ 是类")
现场证据(51de3b6d 的 [DIAG-decl] 报文,随 Traceback 输出):
实参类=5df907d3a02a0bac.Constant | structs=有 |
_struct_sha1_map=5df907d3a02a0bac | class_sha1_map=5df907d3a02a0bac |
symtab[IsStruct=False, IsEnum=True, IsEnumMember=True, Base=CEnum] |
声明函数类型=i8* (i32*) | 声明来源=..._EmitExternalFuncDeclLlvm <- _get_or_declare_function
修后 `ResolveAnnotationType(rawptr[Constant])` 得 CStruct/1 ⇒ _ctype_to_llvm 取
structs['Constant'] ⇒ 声明变为 i8* (%"5df907d3a02a0bac.Constant"*),与实参同型。
|
2026-09-28 22:44:20 +08:00 |
|
TermiNexus
|
51de3b6dcf
|
chore(tpc): [临时诊断] 声明来源 + i32* 形参判定依据并入 fail-fast 报文
只为定位"跨模块函数形参退化成 i32*"(现场 function_get_name 第 0 形参 i32*,
实参 %"46c7dc5230ea5a52.Function"*)。静态排查已穷尽:_ctype_to_llvm /
_type_str_to_llvm 产生 i32* 的出口只有「BaseType 退化成 i32 + PtrCount=1」
(含 CTypeInfo.ToString() 的 'CInt *' → i32*)与「IsEnum + Name + PtrCount=1」,
离线复现不出,需要运行时证据。
做法:把判定依据直接拼进 FailFastError 报文,使其随 Traceback 一起被看到:
[DIAG-decl] 实参类 / structs / _struct_sha1_map / class_sha1_map /
symtab 标志 / 声明函数类型 / 声明来源(创建者调用栈)
并在四个声明创建点记录首个创建者:
FuncGen._get_or_declare_func / get_or_declare_c_func、
BaseGen._get_or_declare_function、HandlesBase.GetOrCreateFuncDecl(会替换声明)。
定位完成后整体回滚(连同记录点)。
|
2026-09-28 22:20:09 +08:00 |
|
TermiNexus
|
bb05a157a6
|
fix(tpc): 收紧「有类定义 ⇒ 是类」判据:排除枚举类型本身
a 编译器缺陷(我上一轮 61f074ff / 3ca46c01 引入的过宽判据):判据用的
_struct_sha1_map 是 _build_struct_sha1_map 按 .vpi/.pyi 里**全部 ClassDef** 建的
⇒ **枚举类**(class ASTKind(t.CEnum)、class LogLevel 等)也在其中。于是
`x: ASTKind` 这类枚举注解被当成结构体建成 opaque struct,与「枚举宽度 = i32」
错位,现场表现为 i32 ↔ 结构体互换:
AttributeError: IntType object has no attribute is_opaque
(llvmlite builder.store / LoadInstr 把 i32 值当指针用)。
收紧为判据分工(两处同口径):
· HandlesTypeMerge._GetCTypeInfoInternal 的 Name 分支:Entry.IsEnum ⇒ 枚举类型,
不进「类定义」分支(走下方 IsEnum 分支,宽度 i32 等);
· BaseGen._get_or_create_struct:_known_class_name 追加 and not Entry.IsEnum。
「裸名被枚举**成员**占住」(Entry.IsEnumMember,如 ast/base.vp 的
Constant: t.State vs ast/exprs.vp 的 class Constant)仍让位给类定义 —— 这正是
原修复要解决的那一类,不受影响。
|
2026-09-28 21:57:21 +08:00 |
|
TermiNexus
|
e6451a077e
|
fix(tpc): 继承展平沿继承链补真实字段名(消除 __inherited_N 占位名)
a 编译器缺陷:泛型基类的继承字段在导入侧展平时名字丢失。父类是泛型特化
`GSListNode[ParamNode]`,其特化体不在任何 .vpi 中 ⇒ 按特化名加载必落空 ⇒ 占位符
路径按 struct 槽位数补 `__inherited_N`:偏移对、**名字丢**。于是继承字段的属性访问
找不到字段(现场 `[fast-fail] 属性 Next 在类 ParamNode 中找不到
(class_members=[__inherited_0, Ty])`)。
语义修正:新增 _ResolveInheritedFieldNames —— 按**声明顺序**沿继承链取父类声明里的
字段名;父类是泛型特化 `X[Arg]` 时回退用**模板名** X 加载其成员(模板声明了字段名,
如 linkedlist.vp:265 `GSListNode[T]: Next: T*` 的 Next),这正是编译期唯一可信的
名字来源;与 DeclarationGenerator._get_inherited_members(stub 端取模板成员)、
BaseGen._get_or_create_struct 的 `_struct_sha1_map` 拼名规则同一条"类名 → 模板/模块"
规则源。名字取不到才退回占位名(仅保证偏移)。
同时修正占位符配对的槽位起点:有 vtable 指针时首元素是 vtable,上面已把它从
_num_elements 扣掉,配对结构体元素必须同步右移一位(原实现从 elements[0] 起取,
会把 vtable 指针的类型当成第一个继承字段的类型)。
结果:展平表直接是 `[("Next", <槽位类型>), ("Ty", ...)]`,属性访问是普通表命中,
不再依赖任何查找期回退。
|
2026-09-28 21:46:30 +08:00 |
|
TermiNexus
|
61f074ffa4
|
fix(tpc): Name 注解路径的类/枚举同名判据补齐 _struct_sha1_map
a 编译器缺陷:HandlesTypeMerge._GetCTypeInfoInternal 的 ast.Name 分支在「类名与
枚举成员同名」时只查 Gen.structs,漏了 Gen._struct_sha1_map(跨模块类只登记了
类名→模块 sha1、本模块尚未建出结构体)。同文件的 Attribute 分支(L241-269)与
HandlesClassDef._HasClassDefinition、TypeConvert._type_str_to_llvm_base 的
同一判据都是「structs 或 _struct_sha1_map」,Name 路径独缺,属判据分裂。
现场:rawptr[Constant](includes/ast/exprs.vp:59 accessor,class Constant 声明在
同文件更后面)在导入侧解析时,先命中平坦符号表里的枚举成员 Constant: t.State
(ast/base.vp)→ 返回枚举 → 与 t.CPtr 合并后经 _ctype_to_llvm 的 IsEnum 分支
(枚举名未登记 ⇒ 宽度退化为 i32)得 i32*,与调用点实参 %"<exprs_sha1>.Constant"*
分裂 → FuncGen._adjust_args 报「指针隐式转换已禁止」。
补齐后 BaseType=CStruct(Constant),_get_or_create_struct 按 _struct_sha1_map 拼出
"<exprs_sha1>.Constant"(BaseGen.py:527-528),与声明端/实参同一结构体对象。
|
2026-09-28 19:40:06 +08:00 |
|
TermiNexus
|
b3f72d675b
|
fix(ctx): 方法体编译失败路径也复位「当前方法」上下文,修 self 被按内层特化类解析
现象:编译 ExprGenFstr.translate_joined_str 时 self.Gen 被按 list[cfc4ca8da95a30e1.AST*] 解析 → 属性在类中找不到(连带错误)。
链路:parts.get(pi) 触发泛型特化按需补全(HandlesExprCall._try_complete_generic_specialization)→ 内层 list[...] 方法发射时 _EmitFunctionLlvm 先置 _CurrentCpythonObjectClass = 内层类(HandlesFunctions:1978)→ 方法体编译失败只 re-raise,末尾的类名/var_struct_class 复位被跳过 → 上层调用点**吞掉**该异常继续编译外层方法,于是外层 self.X 全按内层类解析、后续指令也会误插进内层函数的块。
两处修复:① _try_complete_generic_specialization 的 except 里同时复位 Gen.builder/func 与 _CurrentCpythonObjectClass/Gen._current_class_name(该点会吞异常,必须自己收尾);② _EmitFunctionLlvm 的失败路径在 re-raise 前复位 Gen._current_class_name / _CurrentCpythonObjectClass / var_struct_class / global_struct_class(对所有吞异常的调用点都成立)。
|
2026-09-28 16:52:03 +08:00 |
|
TermiNexus
|
49ff1b995f
|
fix(cast): 显式指针 cast 一律放行(按 bitcast 重解释)+ MemoryOps 改用 vast 解析器模块
① 新增 _IsExplicitPtrCastNode:值节点是写明的指针转换调用(t.CPtr(x)/CPtr(x)/c.CPtr(x)/rawptr[T](x)/t.CPtr[T](x)/(T*)x/T*(x))时,_ClassifyPtrImplicitConvert 直接放行(用户规则「显式转换都可以」),调用方按既有 bitcast 重解释;非 cast 调用(MemBuddy(x)/list[X](x)/foo(x))不受影响。
根因:includes/_list.vp:60 的 elem_ptr: T | t.CPtr = t.CPtr(地址) 在 list[X*] 特化下 T|t.CPtr = X**(T 本身是指针),而 t.CPtr(...) 的值是 i8* ⇒ 被判「层数不同」,与报错自己给的「如需转换请显式 cast(如 t.CPtr(...))」建议自相矛盾(ExprGenFstr.vp 编译失败的 2 条 elem_ptr 报错)。
② MemoryOps.py 的 import ast 是标准库 —— 但 TPC 全部源码由 vast 解析,节点类为 lib.vast.Nodes.*,与标准库 ast 互不兼容 ⇒ 该文件所有节点类型判据对 Viper 源码静默失效(_value_node_of 子表达式下沉、_CtorCallStructType 构造物化豁免、以及新增的 cast 判据都不生效)。改为 import vast as ast,一并修复。
|
2026-09-28 16:48:52 +08:00 |
|
TermiNexus
|
809f9d08fa
|
feat(len): len() 对「非 i8 裸指针 / 无 __len__ 的 struct」改为 fail-fast(对齐 TransPyV)
旧实现:非 i8 裸指针(如 []T 形参实为 T*)静默返回常量 0;struct 无 __len__ 时回落 strlen —— 两者都用假长度掩盖错误。
新口径(两侧逐字一致):定长数组/数组指针 → 常量 N;i8*(str/bytes)→ strlen;带 __len__ 的结构体 → 调 __len__;其余一律编译期 TypeError。
新增 _LEN_SUPPORTED_HINT 共享提示语 + _FailFastLenUnsupported 出口(含 行:列 + 源码片段 + 正确做法)。HandlesExprCall.py 为同源死代码副本,一并同步语义未删。
|
2026-09-28 15:53:02 +08:00 |
|
TermiNexus
|
d7158bd336
|
feat(cast): 指针隐式转换新规则 + None 可隐式转任意类型 + 诊断错位修复(9 文件)
MemoryOps._ClassifyPtrImplicitConvert:同类型放行;层数不同禁;任一侧通用指针(i8*)放行;皆非通用按被指类型(非基本类型禁、基本标量按位宽无损);指针与非基本值互换禁
_IsNoneValue 收敛:AST None 常量 或 指针型 null 常量 → 放行任意目标(指针目标给 null,非指针目标给零值);整数 0 不误命中;短路口覆盖 9 处禁令
诊断:新增 BaseGen._DescribeValueNode(子表达式下沉 + 有符号列号 + 源码片段),9 处禁令统一使用,不再打印外层 Assign 与 4294967295 列号
注:TPC 侧规则③比 TPV 更严(指针→非基本值恒禁),可能与既有按值回读冲突;待实机编译确认后再统一两侧口径
|
2026-09-28 15:10:39 +08:00 |
|
TermiNexus
|
35de6321f6
|
refactor(return): 移除 @c.CReturn 多返回值处理器,只保留 -> tuple[ty1, ty2, ...],遇到 CReturn 一律报错
DeclarationGenerator:tuple[...] 分支逐字保留(仅 CReturnTypes 机械改名 MultiRetTypes),装饰器分支改为 SyntaxError,报文含函数名与“请改用 -> tuple[ty1, ty2, ...]”提示
HandlesAssign(a, b = f() 解包路径):删除装饰器收集分支并改为报错;tuple[...] 恢复与逐个解包逻辑逐字不变
HandlesFunctions:新增 _CRETURN_REMOVED_HINT 与 _RejectCReturnDecorator,在函数定义入口(_GetFunctionSignatureLlvm / _EmitFunctionLlvm)fail-fast——即使只有装饰器、没有 -> 注解,也不会让返回类型静默退化成 i32
HandlesImports:外部函数声明处同样报错,并删除下游已失效的 CReturnTypes 参数拼接死代码
HandlesReturn / HandlesFor / BaseTranslator:CurrentCReturnTypes 等机械改名(读写端一致,无行为变化)
includes/c.py:保留 CReturn 名字作墓碑(删掉会让 @c.CReturn 变成未知属性、可能被静默忽略),docstring 写明已移除并指路 -> tuple[...];README 措辞同步
|
2026-09-28 13:57:04 +08:00 |
|
TermiNexus
|
f9957787a0
|
feat(codegen): TPC 模块级 t.State 全局只声明不定义(external linkage)
extern 名字: 类型的展开产物(名字: 类型 | t.State):本模块生成 @名字 = external global T,不写定义(否则 duplicate symbol)
位置早于「已存在则升级 common 定义」分支,避免 extern 被反向升级成定义;与 import 侧 _EmitExternalGlobalDeclLlvm 同名分支同口径
export(t.CExport)侧无需改动:TPC 模块级全局本就用裸名(_mangle_name 不作用于全局变量),裸名导出语义天然满足
|
2026-09-27 18:01:49 +08:00 |
|
TermiNexus
|
e1a2821bff
|
fix(tpc): 函数声明创建幂等化,消除 DuplicatedNameError
同名声明只在 module.globals、不在 Gen.functions 时,旧代码会再走 ir.Function,而 llvmlite 的 NameScope 按名字去重(GlobalValue.deduplicate_name=False)必抛 DuplicatedNameError。GetOrCreateStubFuncDecl(含 check_existing=False 路径)、GetOrCreateFuncDecl、win32console 内建声明、output-stub 按需载入四处统一先复用 module.globals。真实事故:VarGenMixin.vp 同一模块两处 self.Gen.ExprGen.translate_value(...) 都走 check_existing=False,第二处崩在 llvmlite。
|
2026-09-27 16:18:37 +08:00 |
|
TermiNexus
|
e33ac795ed
|
fix(codegen): 指针强转基座 T*(x) 的字段写入补联合类名通道
与读取侧 _handle_attr_call_result 的联合分支同口径:_get_attr_ptr 新增 Call 基座分支,用 _extract_union_base_class 取裸类名后 bitcast/inttoptr 回 Ptr(类) 再 GEP 成员。此前写入侧只认 Name/Attribute/Subscript,强转基座的字段写入静默返回 None。
|
2026-09-27 16:02:40 +08:00 |
|
TermiNexus
|
5825e7e000
|
feat(codegen): 单目 & 支持对构造调用/函数调用结果取址
与 TransPyV 侧 ExprGenOps._addrof_of_call 同口径:复用 _HandleUnaryOpLlvm 已求值的 OperandVal;构造调用 _HandleClassNewLlvm 返回临时对象的 Ptr(Struct),原样返回;其它类型落到 allocaEntry 临时槽。避免二次求值导致 __before_init__/__init__ 跑两遍。
|
2026-09-27 15:16:08 +08:00 |
|
TermiNexus
|
3b5d85ce9d
|
fix(handles): 补指针操作符目标写入与实参解引用,消除静默丢弃
- HandlesAssign: 新增 ast.UnaryOp 赋值目标分支(*p = v 复用 _StoreWithCoerce);Tuple/List 目标合并;删除 Tuple 分支里未绑定的死代码(UnboundLocalError)
- HandlesAugAssign: 新增 ast.UnaryOp 目标分支实现真 *p += v,其余形态 fail-fast
- HandlesExpr: 新增 ast.Starred 分支,值位置 *p 归一为 UnaryOp(Deref)(修 t.CPtr(*((uint64*)(blk))) 恒为 0)
|
2026-09-27 00:19:44 +08:00 |
|
TermiNexus
|
58050a1ab2
|
fix(member_base): base 改由声明类型与 elements 的一致度校准,修整类字段偏移整体差 1
delta 长度启发式只在成员表与布局恰好差 vtable 一项时成立;成员表多/少一个非 vtable 项时 base 判错,整个类字段偏移整体平移:ast.Constant 的 lineno 落到 pool(MemManager*),调用点报形参 lineno: i32 收到指针,把真因掩盖成指针/整数错配
改法:对 b 属于 {0,1,2} 逐项比较成员声明类型与 elements[b+i],取一致度最高者(完全相同 +2),仅在明显更优(至少多对齐 1 个成员)时覆盖启发式;指针槽区分度最高
同时移除上一轮临时加的运行时字段布局探针(_diag_member_layout 及其两处调用)
|
2026-09-26 21:29:28 +08:00 |
|
TermiNexus
|
50cea6c7b3
|
fix(classdef,base,attr): 成员注解解析静默兜底改 fail-fast;新增按需输出的字段布局探针
HandlesBase.CollectAnnAssignMember: 注解解析返回 None / _ctype_to_llvm 得 void / 抛异常三处静默 i32、i8* 兜底改 fail-fast,报错带成员名+注解原文+BaseType/PtrCount 现场
HandlesClassDef: 方法内 self.x: T = ... 的同类三处兜底同样改 fail-fast(带类名/成员名/注解原文)
HandlesExprAttr: 新增 _diag_member_layout(默认静默,仅当 offset 为 None / members[offset] 名不符 / 类型与 elements[offset] 不一致时打一行,上限 15 行)
|
2026-09-26 21:25:52 +08:00 |
|
TermiNexus
|
c83fc752c6
|
fix(sizeof,parse): 尺寸链去静默兜底,解析报错可定位,补 C 解析器缺口
StructGen: _get_struct_size/_get_align 去 opaque→8/ptr_size、未知→4 兜底并补 VectorType;LiteralStructType.fields→.elements(llvmlite 无 fields,必然 AttributeError)
HandlesClassDef: union 载荷尺寸经不存在的 ir.DataLayout 静默退化成 8 字节;HandlesExprCall/ExprBuiltin: sizeof 各静默 0 分支改 fail-fast,数组元素 sizeof 统一走 _get_struct_size
HandlesFor: nonlocal struct/array 堆分配不再退化成 malloc(8)
vast/vast_c: 补一元 * / & 解析,装饰器后 extern/export 分派修复,C 侧报错带 token 与行号;StubGen.Converter: 宏展开丢尾随空行修 .pyi 缩进非法
其余为 rawptr 迁移 / fail-fast 口径等历史改动一并入库
|
2026-09-26 19:27:22 +08:00 |
|
TermiNexus
|
f7ace9876d
|
fix(vararg): va_arg/arg 类型解析改走注解解析同源并 fail-fast
- _resolve_vararg_type 覆盖 builtins/库/符号表 typedef 与 T* 指针后缀,不再对手抄名单之外的名字(如 uint64)静默回退 i32
- i32 回退会让 Win64 8 字节变参槽被 trunc 丢高 32 位:viperlib vsnprintf 的 %016llx 因此只打印低 32 位,ConstFloat 的浮点常量名(即常量值)退化为真值低 32 位零扩展,double 字面量全变 0.0
- _HandleArgLlvm / _infer_vararg_type_from_context 统一调同一入口,消除三份同源重复解析链
|
2026-09-24 20:41:05 +08:00 |
|
TermiNexus
|
2cc816ac13
|
修复了一些错误
|
2026-09-18 20:00:59 +08:00 |
|
TermiNexus
|
6af2dea917
|
修复了一些问题
|
2026-09-17 14:52:37 +08:00 |
|
TermiNexus
|
43e7cdd2cc
|
feat(tpc): 函数级 DWARF 调试元数据 + 合并 IR 元数据规整
DWARF: 新增 LLVMCG/DebugInfo.py(DebugInfoEmitter)——每模块一个 DIFile/DICompileUnit、每个 define 一个 DISubprogram 并在函数入口首条指令挂 DILocation,模块落盘前补 !llvm.dbg.cu 与 !llvm.module.flags(Debug Info Version 3)。开关:新增 --dwarf(默认关闭),dwarf_enabled = args.dwarf or args.asan,沿 Phase2Translator → _translate_file → Translator.DwarfEnabled → LlvmCodeGenerator.dwarf_enabled 下传。define 之外的 declare 不挂。include 库刻意不给 DI(其 .obj 进跨项目共享的 includes.binary 缓存,注入会污染缓存)
关键约束(踩过的坑,已在探针中实测):DICompileUnit 与 DISubprogram 必须 is_distinct=True;emissionKind 用 FullDebug 而非 Full;spFlags 用 DISPFlagDefinition;DISubprogram 必带 type=DISubroutineType,缺了 llc 会崩 0xC0000005;模块级必须有 !llvm.dbg.cu + Debug Info Version 3
IRMetadataFix: 新增 SanitizeIRMetadata,在 _llc_compile 入口统一规整 IR——BuildCombinedIR 是多模块 IR 文本直接拼接,--dwarf 后每个片段自带 !0..!N 与两份命名元数据,22383 行样本里 !0/!1 各重复 67 次导致 opt/llc 报 Metadata id is already used。实现:按块重编号 !N 并改写 !dbg/命名元数据引用、!llvm.dbg.cu 全量聚合、其它命名元数据全同去重;无元数据文件逐字节 no-op、幂等(1.7MB/0.30s)
顺带修 _AddWeakComdat:函数头正则跨行吞换行,--dwarf 把 !dbg 放到 define 行尾后 comdat 被插到 ! 附着之后,llc 报 expected { in function body(现场 52 个 define 中 36 个中招);改为插在附着之前,无 !dbg 时产物逐字节不变
已自证:llc/opt RC=0、行表含 .vp 文件名与行号、opt -passes=forceattrs,asan 与 llvm-link/always-inline 均不丢 !dbg。已知待办:llc 现报 inlinable function call ... must have a !dbg location ⇒ 需补语句/调用点级 !dbg(否则警告 ignoring invalid debug info 会丢弃整份 DI)
|
2026-09-16 19:29:51 +08:00 |
|
TermiNexus
|
033c0a7771
|
fix(tpc): 修复 t.CVoid 清理暴露的三处类型解析缺口
SymbolTypeResolver: 裸 t.CPtr 作 typedef 值(无联合、无下标)时按 void* 展开。_find_base_type 把 attr==CPtr 归一为小写 ptr,而守卫 _PTR_MODIFIERS 写的是 CPtr 命不中,导致 ptr 被当成类型名存进 OriginalType,最终建成 %"<模块sha>.ptr" 幻影结构体(HANDLE/VOIDPTR/DIR 报 cannot store i8* to ...ptr*)。改前 t.CVoid | t.CPtr 走 BinOp 分支恰好绕过
HandlesExprAttr: 属性访问的成员查找补继承链回退(对齐 HandlesExprUtils._get_var_class 的口径)。字段声明在基类时元素类表的键是声明类,而收件人是子类,原实现只查收件人类自身;方法调用侧早已做 MRO 查询,故 150 处 self.Gen.X.method() 未暴露。修后 self.Gen.TypeGenCType.ImportAliasBuf 可解析(该字段在基类 TypeGenBase),且此前被静默丢弃的 _register_import_alias malloc 分支恢复生效
TypeConvert._base_ctype_to_llvm: 注册表给出完整类型串(CPtr/CArrayPtr/CNeedPtr/CAutoPtr -> i8*)时不再返回 None(_llvm_str_to_ir 只认标量名),改走 _type_str_to_llvm——与同文件 _basic_type_to_llvm 既有口径一致;否则 PtrCount 循环会构造 ir.PointerType(None)(llvmlite opaque 指针,无 .pointee),在 HandlesFunctions._GetFunctionSignatureLlvm 抛 AttributeError(opendir 的 FATAL)。触发集合经全注册表扫描恰好 4 个类
等价性验证: 31614 个符号 + 37527 个真实注解点位逐条对比改前/改后差异 0 条(崩溃输入除外,由 opaque ptr 变为 typed i8**)
|
2026-09-16 18:16:38 +08:00 |
|
TermiNexus
|
0721568d41
|
fix(codegen): 消除泛型特化静默兜底并修正 sha1 前缀归一
崩溃根因(已由 IR + 符号化确证):MatchGenMixin._handle_renum_match 的 body_list.get(bi) 被分派到 list[int].get,返回 i32 后 inttoptr 成 AST* 造成指针 32 位截断,运行期读 vtable 崩溃(ASan 坏地址 0xc1158310)。
第 1 步 方法分派:删除「ClassName 不含 [ 时按 Gen.structs 迭代顺序任选特化」的静默兜底,改为按接收者 LLVM 值类型的 pointee 用 find_struct_by_pointee 身份匹配反查唯一特化;反查不到时以「基名匹配且存在目标方法」求唯一候选,候选多于一个即 fail-fast,不再任选。
第 2 步 泛型实参:5 处「解析不出类型实参就补 int/CInt」改为 fail-fast。经核对语言与实现(wiki 类型系统/类章节、_generic_class_templates 的 type_params 无默认值机制、list 模板仅 1 参)确认泛型不存在合法缺省实参,5 处均属未知兜底。
第 3 步 注解赋值(真正的污染写入点):HandlesAnnAssign 中 bnm 与 CN 的比较未归一 sha1 模块前缀(注解侧裸名 list 与带前缀键 CN 恒不等),导致恢复特化名分支不命中、把裸泛型基名写入 var_struct_class,从而被第 1 步的兜底按顺序任选成 list[int]。改为与同函数既有 _cn_short 口径比较,构造仍用带前缀 CN。
|
2026-09-14 16:45:26 +08:00 |
|
TermiNexus
|
2021c0edb7
|
feat(hotspot): 新增 --hotspot-sites 逐调用点计数并带源码 file:line
为匹配白名单的直接 call 点插桩 internal i64 __fhs_site_<K>(call 前 +1),计数天然包含循环内放大的真实执行次数,可把热点定位到具体调用点。
新增 --hotspot-callees 覆盖白名单、--hotspot-sites-all 全量;按去 16 位 sha1 前缀后的基名匹配。Ctrl+C 落盘独立文件 hotspot_sites.txt(# sites 分段,含调用方/被调方/计数/源码位置),按计数降序;不破坏既有 hotspot.txt 格式。
在 AST->IR 生成期由 _HotspotSiteBuilder 为每条新生成的 call 指令轻量挂载 _src_file/_src_line,插桩时作为可选尾字段输出;取不到则留空不伪造。开关关闭时改用原生 ir.IRBuilder,零影响。
|
2026-09-13 23:29:32 +08:00 |
|
TermiNexus
|
0ffaadc95e
|
fix(tpc): 注解侧泛型基名方向判定,阻止裸泛型 RHS 覆盖已特化注解类型
HandleAnnAssign 原无条件以 RHS.pointee 重建 alloca,会把注解已解析出的 Base[...] 特化类型覆盖成裸泛型基类,导致后续 .get() 按错误元素类型分派(list[int].get 返回 i32)后 inttoptr 截断。新增注解侧泛型基名结构性识别,仅拦此方向错误。
|
2026-09-13 17:50:02 +08:00 |
|
TermiNexus
|
355811d64e
|
chore(tpc): 移除属性链/调用分派错误路径的临时诊断打点
- HandlesBase: 删除 _AttrFailDiag 现场诊断(含模块别名链逐跳 dump),恢复精简错误信息
- HandlesExprAttr: 删除 [CHAIN-DBG] stderr 打点与 [attr-diag]/[attr-diag-nested] KeyError 包装
- HandlesExprCall: 删除 Unknown module 异常的 _rc_note 诊断后缀
|
2026-09-12 12:50:35 +08:00 |
|
TermiNexus
|
ed3355202a
|
fix(tpc): Mod.Var 链属性访问补第四条类回退(直读 var_/global_struct_class)
|
2026-09-12 12:42:59 +08:00 |
|
TermiNexus
|
015fbf17cf
|
fix(tpc): 跨模块模块级变量类登记与 Mod.Var.Field 链解析;并停止跟踪 __pycache__/*.pyc
|
2026-09-12 11:51:42 +08:00 |
|
TermiNexus
|
9257dd841f
|
fix(tpc): rowptr[X] 字段 element_class 登记补短名模糊扫描,修 Unknown module 误报
|
2026-09-12 11:24:49 +08:00 |
|
TermiNexus
|
cc2f5d34eb
|
feat(tpc): includes 只认项目配置;ASan 改为显式链接 clang64 运行库
includes 目录不再回退仓库硬编码 TransPyCRoot/includes:Phase2Translator 新增 PROJECT_INCLUDE_DIRS(INCLUDE_DIRS 置空以兼容旧引用),Config.py 从 project.vpj 的 includes 同步;HandlesImports 的模块搜索、TypeAnnotationResolver._builtins_include_dirs 一律只读项目目录。
ASan:mingw64 clang 没有 x86_64-w64-windows-gnu 目标的 ASan runtime,新增 _FindAsanRuntimeDir 定位 clang64 运行库并按 -l: 显式链接(asan_dynamic-x86_64.dll.a + runtime_thunk),定位失败即报错退出。HandlesExprFormat:i32 不再写 'l' 长度修饰符(LP64 下 printf 会按 64 位读实参)。
|
2026-09-11 22:47:21 +08:00 |
|
TermiNexus
|
a433f79f54
|
基线重置,TransPyC 不再作为直接脚手架主仓库
|
2026-09-09 14:44:44 +08:00 |
|
TermiNexus
|
0bda395ecc
|
fix(translator,peephole): TPC 属性链解析修复与窥孔 T1-T3 收尾
- TPC(lib/core): 泛型父特化形参按声明类登记 var_struct_class; _find_struct_key 键归一支持方括号内嵌 sha 前缀; 字段探测失败不再冒泡 FuncGen fail-fast; cast 局部通用指针槽按静态类 bitcast; 属性解析失败附诊断
- 窥孔(includes/llvmlite/__function.vp): 窥孔移至 Renumber 前使输出 SSA 编号连续; T3 no-op bitcast 消除; T4(数组 bitcast->GEP)验证干扰返回类型收敛已移除
- 附调试打点与 1.log
|
2026-09-08 12:52:48 +08:00 |
|
TermiNexus
|
76d1ee6076
|
fix(compiler,peephole): TPC 属性链解析与窥孔输出瘦身
- TPC(lib/core): 任意级属性链按链前向类解析恢复 stub 退化字段; cast 局部 rowptr[X] 登记回填; 通用指针槽按静态类名 bitcast 兜底; 赋值 RHS 求值失败 fail-fast 防未初始化变量; 报错行按源码文本锚定并附 ATTR-DIAG 现场
- 窥孔(includes/llvmlite/__function.vp): 成员访问单级链模式; 窥孔移至 Renumber 前使 SSA 编号连续; T3 no-op bitcast 消除; 替换缓冲按最坏上界分配
- __builder/__module/string.vp 配套; 清理 Test 构建产物与 PROF 杂项
|
2026-09-08 11:02:37 +08:00 |
|
TermiNexus
|
45e78ad107
|
基线重置,修复了一些 bug
|
2026-09-07 14:46:02 +08:00 |
|
TermiNexus
|
60dbdfe8d2
|
fix(tpc): 方法调用虚分派——变量与模块短名同名时不误入模块函数路径(base.kind 折叠根因)
|
2026-08-28 10:23:26 +08:00 |
|