From 8ad500c4da792f368a3a55d2176993a52e331d2b Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 5 Aug 2026 20:12:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E7=A8=B3=E5=AE=9A=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E7=BC=96=E8=AF=91=20Test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/StubGen/Converter.vp | 1 + App/lib/StubGen/VpiReader.vp | 1 + App/lib/core/Handles/HandlesClassDef.vp | 341 +++++++++++++++++++--- App/lib/core/Handles/HandlesExpr.vp | 13 +- App/lib/core/Handles/HandlesExprCall.vp | 311 ++++++++++++++++---- App/lib/core/Handles/HandlesFunctions.vp | 17 +- App/lib/core/Handles/HandlesMain.vp | 6 + App/lib/core/Handles/HandlesStruct.vp | 62 +++- App/lib/core/Handles/HandlesTranslator.vp | 34 +++ App/lib/core/IncludesScanner.vp | 7 + App/lib/core/Phase1.vp | 63 ++++ App/lib/core/Phase2.vp | 1 + 12 files changed, 738 insertions(+), 119 deletions(-) diff --git a/App/lib/StubGen/Converter.vp b/App/lib/StubGen/Converter.vp index 7d82eb4..7da4933 100644 --- a/App/lib/StubGen/Converter.vp +++ b/App/lib/StubGen/Converter.vp @@ -107,6 +107,7 @@ _g_pyi_cdefine_found: int = 0 def _lookup_cdefine_for_pyi(name: str) -> int: """从本地 CDefine 表查找常量值(用于 .vpi 生成时的 BinOp 计算)""" import lib.core.Handles.HandlesType as HandlesType + global _g_pyi_cdefine_found val: int = HandlesType.lookup_cdefine_constant(name) if HandlesType.is_cdefine_found() != 0: _g_pyi_cdefine_found = 1 diff --git a/App/lib/StubGen/VpiReader.vp b/App/lib/StubGen/VpiReader.vp index 83f461a..978be78 100644 --- a/App/lib/StubGen/VpiReader.vp +++ b/App/lib/StubGen/VpiReader.vp @@ -7,6 +7,7 @@ import stdio import sys import memhub import llvmlite +import viperlib import w32.fileio as fileio import lib.core.VLogger as VLogger import lib.core.Handles.HandlesType as HandlesType diff --git a/App/lib/core/Handles/HandlesClassDef.vp b/App/lib/core/Handles/HandlesClassDef.vp index 22590f5..fed8d06 100644 --- a/App/lib/core/Handles/HandlesClassDef.vp +++ b/App/lib/core/Handles/HandlesClassDef.vp @@ -5,6 +5,7 @@ import llvmlite import memhub import string import stdio +import stdlib import viperlib import lib.core.VLogger as VLogger import lib.core.Handles.HandlesTranslator as HT @@ -1046,6 +1047,12 @@ def _translate_union_def(trans: HT.Translator | t.CPtr, VLogger.error(fb, "UNION") return 0 + # Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活) + if trans._declare_only == 0: + union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, union_ty) + if union_copy is not None: + union_ty = union_copy + # 注册命名结构体到模块 llvmlite.module_add_named_type(trans.Module, pool, union_ty) @@ -1332,6 +1339,13 @@ def _translate_renum_def(trans: HT.Translator | t.CPtr, VLogger.error(fb4, "RENUM") return 0 + # Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活, + # 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效) + if trans._declare_only == 0: + renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, renum_ty) + if renum_copy is not None: + renum_ty = renum_copy + # 注册命名结构体到模块 llvmlite.module_add_named_type(trans.Module, pool, renum_ty) @@ -1450,11 +1464,14 @@ def _register_renum_variants(pool: memhub.MemBuddy | t.CPtr, return # 懒初始化表(首次注册时分配) + # 注意: 必须用 stdlib 分配——这些表在 1b 阶段(mark1 之后)首次分配, + # 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在 + # parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。 if _renum_class_names is None: - _renum_class_names = pool.alloc(8 * RENUM_CLASS_MAX) - _renum_class_variant_counts = pool.alloc(8 * RENUM_CLASS_MAX) - _renum_variant_names = pool.alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) - _renum_variant_tags = pool.alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + _renum_class_names = stdlib.malloc(8 * RENUM_CLASS_MAX) + _renum_class_variant_counts = stdlib.malloc(8 * RENUM_CLASS_MAX) + _renum_variant_names = stdlib.malloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) + _renum_variant_tags = stdlib.malloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS) if (_renum_class_names is None or _renum_class_variant_counts is None or _renum_variant_names is None or _renum_variant_tags is None): _renum_class_names = None @@ -1994,35 +2011,60 @@ def _clone_classdef_for_spec(pool: memhub.MemBuddy | t.CPtr, # ============================================================ # 泛型特化缓存(模块级) +# +# 用扁平 stdlib 数组 + stdlib 深拷贝字符串,保证缓存条目 +# 跨文件永久存活(1b 每文件 reset_to(mark1) 不会回收)。 # ============================================================ -_spec_keys: list[str] | t.CPtr = None -_spec_names: list[str] | t.CPtr = None +SPEC_CACHE_MAX: t.CDefine = 512 +_spec_keys: t.CSizeT | t.CPtr = None +_spec_names: t.CSizeT | t.CPtr = None +_spec_count: int = 0 def _find_cached_spec(spec_key: str) -> str: """查找已缓存的特化名,未找到返回 None""" if _spec_keys is None or spec_key is None: return None - n: t.CSizeT = _spec_keys.__len__() - i: t.CSizeT - for i in range(n): - k: str = _spec_keys.get(i) - if k is not None and string.strcmp(k, spec_key) == 0: - # 用局部变量接收 list.get() 结果,触发旧编译器 inttoptr 类型转换 - spec_nm: str = _spec_names.get(i) - return spec_nm + i: int + for i in range(_spec_count): + key_addr: t.CSizeT = _spec_keys[i] + if key_addr != 0: + k: str = (str | t.CPtr)(t.CVoid(key_addr, t.CPtr)) + if k is not None and string.strcmp(k, spec_key) == 0: + name_addr: t.CSizeT = _spec_names[i] + if name_addr != 0: + return (str | t.CPtr)(t.CVoid(name_addr, t.CPtr)) return None def _cache_spec(pool: memhub.MemBuddy | t.CPtr, spec_key: str, spec_name: str): - """缓存特化结果""" - global _spec_keys, _spec_names + """缓存特化结果(stdlib 深拷贝存储,跨文件安全)""" + global _spec_keys, _spec_names, _spec_count + if spec_key is None or spec_name is None: + return if _spec_keys is None: - _spec_keys = list[str](pool, 8) - _spec_names = list[str](pool, 8) - _spec_keys.append(spec_key) - _spec_names.append(spec_name) + _spec_keys = stdlib.malloc(SPEC_CACHE_MAX * 8) + _spec_names = stdlib.malloc(SPEC_CACHE_MAX * 8) + if _spec_keys is None or _spec_names is None: + return + string.memset(_spec_keys, 0, SPEC_CACHE_MAX * 8) + string.memset(_spec_names, 0, SPEC_CACHE_MAX * 8) + _spec_count = 0 + if _spec_count >= SPEC_CACHE_MAX: + return + # 深拷贝字符串到 stdlib 区 + key_len: t.CSizeT = string.strlen(spec_key) + name_len: t.CSizeT = string.strlen(spec_name) + key_copy: t.CChar | t.CPtr = stdlib.malloc(key_len + 1) + name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1) + if key_copy is None or name_copy is None: + return + string.strcpy(key_copy, spec_key) + string.strcpy(name_copy, spec_name) + _spec_keys[_spec_count] = t.CSizeT(key_copy) + _spec_names[_spec_count] = t.CSizeT(name_copy) + _spec_count += 1 def _specialize_generic_class(trans: HT.Translator | t.CPtr, @@ -2082,6 +2124,10 @@ def _specialize_generic_class(trans: HT.Translator | t.CPtr, if trans._declare_only == 0: pre_existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) if pre_existing is not None and pre_existing.MethodsEmitted == 0: + # 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解 + # 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr) + # 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。 + pre_existing.MethodsEmitted = 1 tp_names_pre: list[str] | t.CPtr = template_cd.type_params spec_cd_pre: ast.ClassDef | t.CPtr = _clone_classdef_for_spec( pool, template_cd, spec_name, tp_names_pre, type_args) @@ -2215,6 +2261,9 @@ def translate_class_def(trans: HT.Translator | t.CPtr, if cd is None or cd.name is None: return 0 + stdio.printf("[VTDBG-STEP] class=%s translate_class_def enter (declare_only=%d)\n", + cd.name, (trans._declare_only if trans is not None else -1)) + pool: memhub.MemBuddy | t.CPtr = trans.Pool class_name: str = cd.name @@ -2244,6 +2293,9 @@ def translate_class_def(trans: HT.Translator | t.CPtr, # 检查是否已注册(用 SHA1 区分跨模块同名类) existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( class_name, trans.ModuleSha1) + stdio.printf("[VTDBG-STEP] class=%s find_struct_by_module returned\n", class_name) + stdio.printf("[VTDBG-STEP] class=%s existing_check done, entry=%p\n", + class_name, existing) if existing is not None: # BUG 5 方案1修改点2:existing 时字段完整性检查 # 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整) @@ -2255,6 +2307,22 @@ def translate_class_def(trans: HT.Translator | t.CPtr, "InternalCompilerError") # 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法 if existing.Ty is not None: + # Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty, + # 其 Name(如 "sha1.ClassName")指向 Phase 1a 的 pool 内存。虽然 mark1 + # 之前分配不被 reset 回收,但 struct_ty 会被后续文件翻译引用(vtable/ + # self 参数类型打印),部分实现下 pool 块被复用导致 Name 悬空崩溃。 + # 保险起见:深拷贝 Name 到 stdlib,确保跨文件永久存活。 + if trans._declare_only == 0: + old_name: t.CChar | t.CPtr = llvmlite.get_struct_name(existing.Ty) + if old_name is not None: + on_len: t.CSizeT = string.strlen(old_name) + on_copy: t.CChar | t.CPtr = stdlib.malloc(on_len + 1) + if on_copy is not None: + string.strcpy(on_copy, old_name) + c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct( + llvmlite.get_struct_fields(existing.Ty), + llvmlite.get_struct_fcount(existing.Ty), + on_copy)) # Phase B: 将已存在的命名结构体注册到当前模块(输出类型定义行) llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) # Phase A-pre(declare_only=1)多遍扫描时,类已注册但不应翻译方法体 @@ -2272,11 +2340,14 @@ def translate_class_def(trans: HT.Translator | t.CPtr, # 否则 find_struct_by_module("GSListNode[Value]") 返回 None # ============================================================ _trigger_base_specialization(trans, cd) + stdio.printf("[VTDBG-STEP] class=%s trigger_base_spec done\n", class_name) # ============================================================ # VTable 检测:判断是否启用虚表 # ============================================================ has_vtable: int = _detect_vtable_status(cd, trans) + stdio.printf("[VTDBG-STEP] class=%s vtable_status done, has_vtable=%d\n", + class_name, has_vtable) parent_name: str = _get_parent_class(cd, trans) is_novtable_deco: int = 0 if cd.decorator_list is not None: @@ -2302,7 +2373,11 @@ def translate_class_def(trans: HT.Translator | t.CPtr, if parent_check is None: parent_check = HandlesStruct.find_struct(parent_name) if parent_check is None: + stdio.printf("[VTDBG-STEP] class=%s parent %s not registered, defer\n", + class_name, parent_name) return 0 + stdio.printf("[VTDBG-STEP] class=%s parent_check done, parent=%s\n", + class_name, parent_name) # ============================================================ # 1. 遍历 class body,收集字段信息 @@ -2325,6 +2400,7 @@ def translate_class_def(trans: HT.Translator | t.CPtr, # ============================================================ # 1.5 继承父类字段(字段展平) + # ============================================================ # # 父类字段排在子类字段之前,结构体布局: # [vtable_ptr?, parent_field1, ..., child_field1, ...] @@ -2514,12 +2590,21 @@ def translate_class_def(trans: HT.Translator | t.CPtr, prev_node = pnode # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" + # 注意: Phase 1b(declare_only=0)时 struct_ty 会注册到全局表并被后续 + # 文件翻译引用(vtable/self 参数类型打印),其 Name 必须跨 1b 每文件 + # reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。 type_name: str = class_name if trans.ModuleSha1 is not None: name_buf: t.CChar | t.CPtr = pool.alloc(64) if name_buf is not None: viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) type_name = name_buf + if trans._declare_only == 0 and type_name is not None: + tn_len: t.CSizeT = string.strlen(type_name) + tn_copy: t.CChar | t.CPtr = stdlib.malloc(tn_len + 1) + if tn_copy is not None: + string.strcpy(tn_copy, type_name) + type_name = tn_copy # 创建 StructType(命名结构体) struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name) @@ -2530,6 +2615,17 @@ def translate_class_def(trans: HT.Translator | t.CPtr, VLogger.error(fb_st, "CLASS") return 0 + # Phase 1b(declare_only=0)新注册的 struct_ty 会被注册到全局表并被后续文件 + # 翻译引用(vtable/self 参数类型打印/find_struct_by_type 指针匹配)。LLVMType + # 对象和 Fields 链是 pool 分配的,本文件 reset_to(mark1) 后悬空。深拷贝整棵树 + # 到 stdlib,并替换 struct_ty 指针,保证 entry.Ty 与调用方持有的 struct_ty + # 指向同一个 stdlib 拷贝(指针匹配不失效)且跨文件永久存活。 + if trans._declare_only == 0: + st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, struct_ty) + if st_copy is not None: + struct_ty = st_copy + type_name = llvmlite.get_struct_name(struct_ty) + # 注册命名结构体到模块(输出 %"name" = type { ... } 定义行) llvmlite.module_add_named_type(trans.Module, pool, struct_ty) @@ -2661,6 +2757,8 @@ def _format_func_type_str(pool: memhub.MemBuddy | t.CPtr, return 0 buf[0] = '\0' + stdio.printf("[VTDBG-FMT] enter func=%p\n", func) + stdio.fflush(None) # 打印返回类型(使用访问器函数避免跨模块直接字段访问) ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) ret_buf: t.CChar | t.CPtr = pool.alloc(128) @@ -2669,23 +2767,42 @@ def _format_func_type_str(pool: memhub.MemBuddy | t.CPtr, llvmlite.TypePrint(ret_buf, 128, ret_ty, pool) _vtable_strcat(buf, buf_size, ret_buf) _vtable_strcat(buf, buf_size, " (") + stdio.printf("[VTDBG-FMT] ret done\n") + stdio.fflush(None) # 遍历参数(使用访问器函数避免跨模块直接字段访问) cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) first: int = 1 param_buf: t.CChar | t.CPtr = pool.alloc(128) + _pc: int = 0 while cur is not None: + _pc += 1 + stdio.printf("[VTDBG-FMT] p%d=%p\n", _pc, cur) + stdio.fflush(None) + if _pc > 100: + stdio.printf("[VTDBG-FUNC-LOOP] func=%p param_chain>100 stop\n", func) + break if first == 0: _vtable_strcat(buf, buf_size, ", ") if param_buf is not None: param_buf[0] = '\0' + stdio.printf("[VTDBG-FMT] p%d get_ty...\n", _pc) + stdio.fflush(None) param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) + stdio.printf("[VTDBG-FMT] p%d ty=%p\n", _pc, param_ty) + stdio.fflush(None) if param_ty is not None: llvmlite.TypePrint(param_buf, 128, param_ty, pool) + stdio.printf("[VTDBG-FMT] p%d str=%s\n", _pc, param_buf) + stdio.fflush(None) _vtable_strcat(buf, buf_size, param_buf) + stdio.printf("[VTDBG-FMT] p%d next...\n", _pc) + stdio.fflush(None) cur = llvmlite.param_get_next(cur) first = 0 _vtable_strcat(buf, buf_size, ")") + stdio.printf("[VTDBG-FMT] done\n") + stdio.fflush(None) return 1 @@ -2710,16 +2827,20 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, pool: memhub.MemBuddy | t.CPtr = trans.Pool mod: llvmlite.LLVMModule | t.CPtr = trans.Module + stdio.printf("[VTDBG-ENTER] class=%s\n", class_name) + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children if children is None: return 0 cn: t.CSizeT = children.__len__() # 1. 收集虚方法信息 - full_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * VTBL_METHOD_MAX) - method_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * VTBL_METHOD_MAX) + # stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活), + # 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。 + full_names_buf: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX) + method_names_buf: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX) # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) - method_parent_sha1s: t.CSizeT | t.CPtr = pool.alloc(8 * VTBL_METHOD_MAX) + method_parent_sha1s: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX) if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None: return 0 string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX) @@ -2750,6 +2871,10 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, parent_vt_count: int = 0 if vt_parent_entry is not None: parent_vt_count = vt_parent_entry.VTableMethodCount + stdio.printf("[VTDBG-PARENT] class=%s parent=%s parent_entry=%p vt_count=%d\n", + class_name, parent_name, vt_parent_entry, parent_vt_count) + stdio.printf("[VTDBG-STEP] class=%s collect-parent done, method_count=%d\n", + class_name, method_count) if parent_vt_count > 0: for pvi in range(parent_vt_count): if method_count >= VTBL_METHOD_MAX: @@ -2789,7 +2914,7 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, full_names_buf[method_count] = t.CSizeT(pfname_buf) # 复制方法名(短名) pmname_len: t.CSizeT = string.strlen(pmethod_name) - pmname_buf: t.CChar | t.CPtr = pool.alloc(pmname_len + 1) + pmname_buf: t.CChar | t.CPtr = stdlib.malloc(pmname_len + 1) if pmname_buf is not None: string.strcpy(pmname_buf, pmethod_name) method_names_buf[method_count] = t.CSizeT(pmname_buf) @@ -2846,7 +2971,7 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, # 复制方法名 mname_len: t.CSizeT = string.strlen(mname) - mname_buf: t.CChar | t.CPtr = pool.alloc(mname_len + 1) + mname_buf: t.CChar | t.CPtr = stdlib.malloc(mname_len + 1) if mname_buf is not None: string.strcpy(mname_buf, mname) method_names_buf[method_count] = t.CSizeT(mname_buf) @@ -2854,9 +2979,12 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, method_count += 1 if method_count == 0: + stdio.printf("[VTDBG-STEP] class=%s collect done, method_count=0 -> return\n", class_name) return 0 # 2. 构造 VTable 类型: { i8*, i8*, ..., i8* } + stdio.printf("[VTDBG-STEP] class=%s collect done, method_count=%d -> build vtable\n", + class_name, method_count) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) @@ -2875,19 +3003,23 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, return 0 # 3. 构造初始化字符串 - init_buf: t.CChar | t.CPtr = pool.alloc(4096) + # 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节, + # 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。 + init_buf: t.CChar | t.CPtr = pool.alloc(16384) if init_buf is None: return 0 init_buf[0] = '\0' - _vtable_strcat(init_buf, 4096, "{ ") + stdio.printf("[VTDBG-STEP] class=%s build vtable-ty done, method_count=%d -> init str\n", + class_name, method_count) + _vtable_strcat(init_buf, 16384, "{ ") for i in range(method_count): if i > 0: - _vtable_strcat(init_buf, 4096, ", ") + _vtable_strcat(init_buf, 16384, ", ") full_name_addr: t.CSizeT = full_names_buf[i] if full_name_addr == 0: - _vtable_strcat(init_buf, 4096, "i8* null") + _vtable_strcat(init_buf, 16384, "i8* null") continue full_name: str = (str | t.CPtr)(t.CVoid(full_name_addr, t.CPtr)) @@ -2909,31 +3041,71 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, if func is None: func = HandlesExprCall.find_func_global(full_name) - if func is None: - _vtable_strcat(init_buf, 4096, "i8* null") + # func 可能已被 1b reset_to(mark1) 回收(跨模块继承方法在定义文件翻译后被 reset)。 + # 悬空指针非 NULL 但内容已被复用,_format_func_type_str 解引用会沿垃圾 Next 链 + # 指针追逐导致无限分配(TypePrint 每次 pool.alloc(512) → 单文件暴涨 900MB OOM)。 + # 因此 func 非 NULL 时也须用 _is_valid_ptr 校验,失败回退到 TypeStr。 + func_valid: int = 0 + if func is not None: + if trans.Pool is not None: + # 继承方法(parent_sha1_addr != 0):func 来自其他模块,该模块 1b 翻译 + # 后已被 reset_to(mark1) 回收,_is_valid_ptr 存在假阳性(块头复用后仍 + # 看似有效),直接判定无效走 TypeStr 回退,避免解引用悬空 func 崩溃。 + if parent_sha1_addr != 0: + func_valid = 0 + elif trans.Pool._is_valid_ptr(func) != 0: + func_valid = 1 + if func_valid == 0: + # 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。 + ge: HandlesExprCall.FuncEntry | t.CPtr = HandlesExprCall.find_func_entry_global(full_name) + stdio.printf("[VTDBG] vtable '%s' method '%s' func=%p valid=0 fallback_ge=%p\n", + class_name, full_name, func, ge) + if ge is not None and ge.TypeStr is not None: + _vtable_strcat(init_buf, 16384, "i8* bitcast (") + _vtable_strcat(init_buf, 16384, ge.TypeStr) + _vtable_strcat(init_buf, 16384, "* @") + if _vtable_name_needs_quote(mangled_name) != 0: + _vtable_strcat(init_buf, 16384, "\"") + _vtable_strcat(init_buf, 16384, mangled_name) + _vtable_strcat(init_buf, 16384, "\"") + else: + _vtable_strcat(init_buf, 16384, mangled_name) + _vtable_strcat(init_buf, 16384, " to i8*)") + continue + _vtable_strcat(init_buf, 16384, "i8* null") continue # 构造函数类型字符串 func_ty_buf: t.CChar | t.CPtr = pool.alloc(512) if func_ty_buf is None: - _vtable_strcat(init_buf, 4096, "i8* null") + _vtable_strcat(init_buf, 16384, "i8* null") continue + stdio.printf("[VTDBG-STEP] class=%s method[%d] %s valid func=%p -> format_func_type\n", + class_name, i, full_name, func) _format_func_type_str(pool, func_ty_buf, 512, func) # 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*) - _vtable_strcat(init_buf, 4096, "i8* bitcast (") - _vtable_strcat(init_buf, 4096, func_ty_buf) - _vtable_strcat(init_buf, 4096, "* @") + stdio.printf("[VTDBG-STEP] class=%s method[%d] bitcast start, ftb=%p mn=%p\n", + class_name, i, func_ty_buf, mangled_name) + stdio.fflush(None) + _vtable_strcat(init_buf, 16384, "i8* bitcast (") + _vtable_strcat(init_buf, 16384, func_ty_buf) + _vtable_strcat(init_buf, 16384, "* @") if _vtable_name_needs_quote(mangled_name) != 0: - _vtable_strcat(init_buf, 4096, "\"") - _vtable_strcat(init_buf, 4096, mangled_name) - _vtable_strcat(init_buf, 4096, "\"") + _vtable_strcat(init_buf, 16384, "\"") + _vtable_strcat(init_buf, 16384, mangled_name) + _vtable_strcat(init_buf, 16384, "\"") else: - _vtable_strcat(init_buf, 4096, mangled_name) - _vtable_strcat(init_buf, 4096, " to i8*)") + _vtable_strcat(init_buf, 16384, mangled_name) + _vtable_strcat(init_buf, 16384, " to i8*)") + stdio.printf("[VTDBG-STEP] class=%s method[%d] bitcast done\n", class_name, i) + stdio.fflush(None) - _vtable_strcat(init_buf, 4096, " }") + _vtable_strcat(init_buf, 16384, " }") + stdio.printf("[VTDBG-STEP] class=%s vtable init str done, len=%d\n", + class_name, string.strlen(init_buf)) + stdio.fflush(None) # 4. 构造 VTable 全局变量名 vtable_name_buf: t.CChar | t.CPtr = pool.alloc(128) @@ -2941,10 +3113,16 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, return 0 viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) vtable_mangled: str = HandlesFunctions._mangle_name(trans, vtable_name_buf) + stdio.printf("[VTDBG-STEP] class=%s vtable name done, mn=%p\n", + class_name, vtable_mangled) + stdio.fflush(None) # 5. 创建全局变量 gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( pool, vtable_mangled, vtable_ty) + stdio.printf("[VTDBG-STEP] class=%s new_global_variable done, gv=%p\n", + class_name, gv) + stdio.fflush(None) if gv is None: return 0 gv.Initializer = init_buf @@ -2953,11 +3131,18 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, # 添加到模块 llvmlite.module_add_global(mod, gv) + stdio.printf("[VTDBG-STEP] class=%s module_add_global done\n", class_name) + stdio.fflush(None) # 6. 存储虚方法名列表到 StructEntry(直接用 entry,规避跨模块同名 find_struct 找错) + stdio.printf("[VTDBG-STEP] class=%s store VTableMethods, entry=%p mnb=%p\n", + class_name, vt_self_entry, method_names_buf) + stdio.fflush(None) if vt_self_entry is not None: vt_self_entry.VTableMethods = method_names_buf vt_self_entry.VTableMethodCount = method_count + stdio.printf("[VTDBG-STEP] class=%s VTableMethods stored\n", class_name) + stdio.fflush(None) return 0 @@ -3051,6 +3236,8 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr, if stmt.kind() == ast.ASTKind.FunctionDef: fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) if fd is not None and fd.name is not None: + stdio.printf("[VTDBG-STEP] class=%s oop loop method: %s\n", + class_name, fd.name) _translate_method(trans, fd, struct_ty, class_name) # 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount) @@ -3070,6 +3257,7 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr, if oop_entry is not None: oop_entry.MethodsEmitted = 1 + stdio.printf("[VTDBG-STEP] class=%s oop_methods done\n", class_name) return 0 @@ -3108,6 +3296,8 @@ def _translate_method(trans: HT.Translator | t.CPtr, self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) method_name: str = fd.name + stdio.printf("[VTDBG-STEP] class=%s translate_method enter: %s\n", + class_name, method_name) # 构建方法全名: ClassName.method_name full_name_buf: t.CChar | t.CPtr = pool.alloc(128) @@ -3165,7 +3355,8 @@ def _translate_method(trans: HT.Translator | t.CPtr, # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) max_funcs: int = 256 if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, - md_defaults, md_default_count, md_param_count) == 0: + md_defaults, md_default_count, md_param_count, + pool) == 0: trans._func_count = func_count + 1 # 添加 self 参数(Ptr(struct_ty)) @@ -3192,6 +3383,9 @@ def _translate_method(trans: HT.Translator | t.CPtr, viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) + # 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用) + HandlesExprCall.update_global_func_typestr(pool, full_name, func) + # 创建 entry 块 entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") if entry_blk is None: @@ -3343,18 +3537,27 @@ def _generate_before_init(trans: HT.Translator | t.CPtr, if trans is None or struct_ty is None or class_name is None: return 0 + stdio.printf("[VTDBG-STEP] class=%s -> before_init\n", class_name) + stdio.fflush(None) + import lib.core.Handles.HandlesFunctions as HandlesFunctions import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesExprCall as HandlesExprCall + stdio.printf("[BI-DBG] step1 pool/mod/funcs ok, func_count=%d\n", trans._func_count) + stdio.fflush(None) pool: memhub.MemBuddy | t.CPtr = trans.Pool mod: llvmlite.LLVMModule | t.CPtr = trans.Module funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs func_count: int = trans._func_count + stdio.printf("[BI-DBG] step2 pool=%p mod=%p funcs=%p ok\n", pool, mod, funcs_ptr) + stdio.fflush(None) self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + stdio.printf("[BI-DBG] step3 Ptr/Void ty ok self_ptr=%p\n", self_ptr_ty) + stdio.fflush(None) # 构建函数名: ClassName.__before_init__ full_name_buf: t.CChar | t.CPtr = pool.alloc(128) @@ -3362,46 +3565,82 @@ def _generate_before_init(trans: HT.Translator | t.CPtr, return 0 viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) full_name: str = full_name_buf + stdio.printf("[BI-DBG] step4 full_name=%s\n", full_name) + stdio.fflush(None) mangled_name: str = HandlesFunctions._mangle_name(trans, full_name) + stdio.printf("[BI-DBG] step5 mangled=%s\n", mangled_name) + stdio.fflush(None) # 创建函数 func: llvmlite.Function | t.CPtr = llvmlite.create_function( pool, mod, mangled_name, void_ty) + stdio.printf("[BI-DBG] step6 create_function done func=%p\n", func) + stdio.fflush(None) if func is None: return 0 # 注册到函数表 max_funcs: int = 256 - if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs) == 0: + rc_add: int = HandlesExprCall.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, None, 0, 0, pool) + stdio.printf("[BI-DBG] step7 add_func_to_table rc=%d\n", rc_add) + stdio.fflush(None) + if rc_add == 0: trans._func_count = func_count + 1 # 添加 self 参数 llvmlite.add_param(pool, func, self_ptr_ty, "%self") + stdio.printf("[BI-DBG] step8 add_param done\n") + stdio.fflush(None) + + # 参数添加完成,补全全局函数表的 TypeStr + rc_ut: int = HandlesExprCall.update_global_func_typestr(pool, full_name, func) + stdio.printf("[BI-DBG] step9 update_global_func_typestr rc=%d\n", rc_ut) + stdio.fflush(None) # 创建 entry 块 + builder entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + stdio.printf("[BI-DBG] step10 create_block entry=%p\n", entry_blk) + stdio.fflush(None) if entry_blk is None: return 0 func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + stdio.printf("[BI-DBG] step11 new_builder builder=%p\n", func_builder) + stdio.fflush(None) if func_builder is None: return 0 llvmlite.position_at_end(func_builder, entry_blk) # 注册 self 为 SSA 值 self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") + stdio.printf("[BI-DBG] step12 SSAValue self_val=%p\n", self_val) + stdio.fflush(None) # 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + stdio.printf("[BI-DBG] step13 ConstZero zero=%p\n", zero) + stdio.fflush(None) if zero is not None: llvmlite.build_store(func_builder, zero, self_val) + stdio.printf("[BI-DBG] step14 build_store zero done\n") + stdio.fflush(None) # 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0) # 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错 + stdio.printf("[BI-DBG] step15 before find_struct_by_type, struct_ty=%p\n", struct_ty) + stdio.fflush(None) bi_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + stdio.printf("[BI-DBG] step16 find_struct_by_type done, bi_entry=%p\n", bi_entry) + stdio.fflush(None) bi_has_vt: int = 0 if bi_entry is not None: + stdio.printf("[BI-DBG] step17 read bi_entry->HasVTable\n", None) + stdio.fflush(None) bi_has_vt = bi_entry.HasVTable + stdio.printf("[VTDBG-STEP] class=%s before_init: has_vt=%d vt_count=%d field_count=%d\n", + class_name, bi_has_vt, + (bi_entry.VTableMethodCount if bi_entry is not None else -1), + (bi_entry.FieldCount if bi_entry is not None else -1)) if bi_has_vt == 1: vt_method_count: int = 0 if bi_entry is not None: @@ -3460,16 +3699,31 @@ def _generate_before_init(trans: HT.Translator | t.CPtr, # 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错) if bi_entry is not None: + stdio.printf("[VTDBG-STEP] class=%s before_init: store-defaults loop start, field_count=%d\n", + class_name, bi_entry.FieldCount) for fi in range(bi_entry.FieldCount): fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( bi_entry, fi) + stdio.printf("[VTDBG-FIELD] class=%s fi=%d fe=%p index=%d default=%p ty=%p\n", + class_name, fi, fe, + (fe.Index if fe is not None else -1), + (fe.DefaultVal if fe is not None else None), + (fe.Ty if fe is not None else None)) if fe is None or fe.DefaultVal is None: continue + # 打印 DefaultVal 的 AST kind(定位悬空/垃圾节点) + dk: int = fe.DefaultVal.kind() + stdio.printf("[VTDBG-FIELD] class=%s fi=%d translate default kind=%d\n", + class_name, fi, dk) # 翻译默认值表达式 default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( func_builder, pool, mod, fe.DefaultVal, None, 0, trans) if default_val is None: + stdio.printf("[VTDBG-FIELD] class=%s fi=%d translate default -> None\n", + class_name, fi) continue + stdio.printf("[VTDBG-STEP] class=%s before_init: field[%d] default translated\n", + class_name, fi) # GEP 到字段 field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( func_builder, struct_ty, fe.Ty, self_val, fe.Index) @@ -3480,6 +3734,7 @@ def _generate_before_init(trans: HT.Translator | t.CPtr, llvmlite.build_store(func_builder, default_val, field_ptr) # 3. ret void + stdio.printf("[VTDBG-STEP] class=%s before_init: done, ret void\n", class_name) llvmlite.build_ret_void(func_builder) return 0 diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index 88e44ff..c84ca82 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -935,9 +935,16 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr, rhs_ptr_level: int = get_ptr_level(rhs.Ty) if lhs_ptr_level != rhs_ptr_level: # 类型不匹配:数值vs指针 或 不同级指针 - VLogger.error( - "比较类型不匹配: lhs 指针层级=%d, rhs 指针层级=%d (禁止数值与指针、不同级指针比较)" % (lhs_ptr_level, rhs_ptr_level), - "Compare") + # 用 fmt_buf 构造可读消息(Viper % 格式化在部分路径生成 null) + fmt_msg: t.CChar | t.CPtr = VLogger.fmt_buf() + if fmt_msg is not None: + viperlib.snprintf( + fmt_msg, 1024, + "比较类型不匹配(行 %d): lhs 层级=%d (ty=%p), rhs 层级=%d (ty=%p)", + cmp.lineno, lhs_ptr_level, lhs.Ty, rhs_ptr_level, rhs.Ty) + VLogger.error(fmt_msg, "Compare") + else: + VLogger.error("比较类型不匹配: 数值与指针/不同级指针比较", "Compare") return None else: # None 比较: None 被翻译为 i8* null(一级指针) diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index f2fff3c..fdbb888 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -2843,18 +2843,24 @@ def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr, if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: mdf_di: int = mdf_pi - mdf_offset if mdf_di < mdf_default_count: - mdf_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(mdf_defaults), t.CPtr)) - mdf_node: ast.AST | t.CPtr = mdf_defaults_list.get(mdf_di) - if mdf_node is not None: - mdf_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, mdf_node, None, 0, trans) - if mdf_val is not None: - llvmlite.value_set_next(mdf_val, None) - llvmlite.value_set_next(tail, mdf_val) - tail = mdf_val - total_count += 1 - mdf_pi += 1 - continue + # 优先用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收) + mdf_val: llvmlite.Value | t.CPtr = None + if mdf_gd is not None: + mdf_val = _build_const_from_snapshot( + pool, mod, mdf_gd, mdf_di, trans, builder) + if mdf_val is None: + mdf_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(mdf_defaults), t.CPtr)) + mdf_node: ast.AST | t.CPtr = mdf_defaults_list.get(mdf_di) + if mdf_node is not None: + mdf_val = HandlesExpr.translate_value( + builder, pool, mod, mdf_node, None, 0, trans) + if mdf_val is not None: + llvmlite.value_set_next(mdf_val, None) + llvmlite.value_set_next(tail, mdf_val) + tail = mdf_val + total_count += 1 + mdf_pi += 1 + continue # 无默认值时用零值兜底(需要 found_func 获取参数类型) if found_func is not None: param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) @@ -3498,18 +3504,24 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset: mdf_di: int = mdf_pi - mdf_offset if mdf_di < mdf_default_count: - mdf_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(mdf_defaults), t.CPtr)) - mdf_node: ast.AST | t.CPtr = mdf_defaults_list.get(mdf_di) - if mdf_node is not None: - mdf_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, mdf_node, None, 0, trans) - if mdf_val is not None: - llvmlite.value_set_next(mdf_val, None) - llvmlite.value_set_next(tail, mdf_val) - tail = mdf_val - total_count += 1 - mdf_pi += 1 - continue + # 优先用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收) + mdf_val: llvmlite.Value | t.CPtr = None + if mdf_gd is not None: + mdf_val = _build_const_from_snapshot( + pool, mod, mdf_gd, mdf_di, trans, builder) + if mdf_val is None: + mdf_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(mdf_defaults), t.CPtr)) + mdf_node: ast.AST | t.CPtr = mdf_defaults_list.get(mdf_di) + if mdf_node is not None: + mdf_val = HandlesExpr.translate_value( + builder, pool, mod, mdf_node, None, 0, trans) + if mdf_val is not None: + llvmlite.value_set_next(mdf_val, None) + llvmlite.value_set_next(tail, mdf_val) + tail = mdf_val + total_count += 1 + mdf_pi += 1 + continue # 无默认值时用零值兜底(需要 found_func 获取参数类型) if found_func is not None: param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) @@ -4947,18 +4959,24 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr, while df_di < df_default_count: df_param_idx: int = df_offset + df_di if df_param_idx >= can: - df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr)) - df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di) - if df_default_node is not None: - df_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, df_default_node, None, 0, trans) - if df_arg_val is not None: - df_arg_val.Next = None - if head is None: - head = df_arg_val - else: - tail.Next = df_arg_val - tail = df_arg_val + # 优先用 stdlib 常量快照重建(gd_entry.Defaults 的 pool 内 AST 可能已被 reset 回收) + df_arg_val: llvmlite.Value | t.CPtr = None + if gd_entry is not None: + df_arg_val = _build_const_from_snapshot( + pool, mod, gd_entry, df_di, trans, builder) + if df_arg_val is None: + df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr)) + df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di) + if df_default_node is not None: + df_arg_val = HandlesExpr.translate_value( + builder, pool, mod, df_default_node, None, 0, trans) + if df_arg_val is not None: + df_arg_val.Next = None + if head is None: + head = df_arg_val + else: + tail.Next = df_arg_val + tail = df_arg_val df_di += 1 # 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi") @@ -5569,6 +5587,10 @@ class FuncEntry: Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值 DefaultCount: int # 默认值数量 ParamCount: int # 形参数量(不含 self) + # TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全) + # 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后, + # vtable 生成 find_func_global 读类型改用此文本,避免悬空。 + TypeStr: t.CChar | t.CPtr # ============================================================ # 初始化函数表 @@ -5610,13 +5632,15 @@ def add_func_to_table(funcs: FuncEntry | t.CPtr, max_count: int, defaults: t.CVoid | t.CPtr = None, default_count: int = 0, - param_count: int = 0) -> int: + param_count: int = 0, + pool: memhub.MemBuddy | t.CPtr = None) -> int: """添加函数到函数表,返回 0 成功 Args: defaults: ast.Arguments.defaults 列表节点指针,None=无默认值 default_count: 默认值数量(len(defaults)) param_count: 形参数量(不含 self,len(args.args)) + pool: 内存池(用于生成 TypeStr;None 时 TypeStr 为空,vtable 回退读 Func 对象) """ if name is None or func is None or funcs is None: return 1 @@ -5631,7 +5655,7 @@ def add_func_to_table(funcs: FuncEntry | t.CPtr, entry.DefaultCount = default_count entry.ParamCount = param_count # 同时注册到全局函数表(供跨模块 vtable 初始化查找) - _register_global_func(name, func) + _register_global_func(name, func, pool) # 同时注册到全局默认参数表(供跨模块调用时填充默认值) if default_count > 0: _register_global_defaults(name, defaults, default_count, param_count) @@ -5662,10 +5686,64 @@ def _init_global_func_table() -> int: _global_func_count = 0 return 1 -def _register_global_func(name: str, func: llvmlite.Function | t.CPtr) -> int: + +# _build_func_type_str — 从 Function 对象生成函数类型文本(stdlib 存储) +# +# 格式: ret_ty (param1_ty, param2_ty, ...),与 vtable bitcast 需要一致。 +# 用 stdlib.malloc 分配返回,跨文件永久存活(1b reset 不回收)。 +# 返回 None 表示失败。 +def _build_func_type_str(pool: memhub.MemBuddy | t.CPtr, + func: llvmlite.Function | t.CPtr) -> t.CChar | t.CPtr: + """生成函数类型文本(stdlib 分配)""" + if func is None: + return None + # 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲 + ty_buf: t.CChar | t.CPtr = pool.alloc(1024) + if ty_buf is None: + return None + ty_buf[0] = '\0' + + # 返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) + ret_part: t.CChar | t.CPtr = pool.alloc(512) + if ret_part is not None and ret_ty is not None: + ret_part[0] = '\0' + llvmlite.TypePrint(ret_part, 512, ret_ty, pool) + string.strcat(ty_buf, ret_part) + string.strcat(ty_buf, " (") + + # 参数类型 + cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + first: int = 1 + param_part: t.CChar | t.CPtr = pool.alloc(512) + while cur is not None: + if first == 0: + string.strcat(ty_buf, ", ") + if param_part is not None: + param_part[0] = '\0' + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) + if param_ty is not None: + llvmlite.TypePrint(param_part, 512, param_ty, pool) + string.strcat(ty_buf, param_part) + cur = llvmlite.param_get_next(cur) + first = 0 + string.strcat(ty_buf, ")") + + # 深拷贝到 stdlib 区(TypeStr 跨文件永久存活) + ts_len: t.CSizeT = string.strlen(ty_buf) + ts_copy: t.CChar | t.CPtr = stdlib.malloc(ts_len + 1) + if ts_copy is None: + return None + string.strcpy(ts_copy, ty_buf) + return ts_copy + + +def _register_global_func(name: str, func: llvmlite.Function | t.CPtr, + pool: memhub.MemBuddy | t.CPtr = None) -> int: """注册函数到全局表(已存在则跳过),返回 0 成功 直接操作全局表,不调用 add_func_to_table,避免递归。 + pool 用于生成 TypeStr(None 时 TypeStr 为空)。 """ global _global_func_count if name is None or func is None: @@ -5681,11 +5759,38 @@ def _register_global_func(name: str, func: llvmlite.Function | t.CPtr) -> int: entry_size: t.CSizeT = FuncEntry.__sizeof__() entry_addr: t.CUInt64T = t.CUInt64T(_global_funcs) + _global_func_count * entry_size entry: FuncEntry | t.CPtr = (FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - entry.Name = name + # Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件 + # reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃) + name_len: t.CSizeT = string.strlen(name) + name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1) + if name_copy is None: + return 1 + string.strcpy(name_copy, name) + entry.Name = name_copy entry.Func = func + # TypeStr 不在此生成:函数参数在 add_func_to_table 之后才添加, + # 需由调用方在参数添加完成后调用 update_global_func_typestr 补全。 _global_func_count += 1 return 0 + +def update_global_func_typestr(pool: memhub.MemBuddy | t.CPtr, + name: str, + func: llvmlite.Function | t.CPtr) -> int: + """更新全局函数表的 TypeStr(在函数参数全部添加完成后调用) + + 调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。 + 生成 ret_ty (param1_ty, ...) 类型文本(stdlib 深拷贝), + 供 vtable 生成在 func 被 1b reset 后使用。 + """ + if name is None or func is None: + return 1 + entry: FuncEntry | t.CPtr = find_func_entry_global(name) + if entry is None: + return 1 + entry.TypeStr = _build_func_type_str(pool, func) + return 0 + def find_func_global(name: str) -> llvmlite.Function | t.CPtr: """在全局函数表中按名称查找,返回 Function 指针或 None""" if name is None or _global_funcs is None: @@ -5693,6 +5798,20 @@ def find_func_global(name: str) -> llvmlite.Function | t.CPtr: return find_func_in_table(_global_funcs, _global_func_count, name) +def find_func_entry_global(name: str) -> FuncEntry | t.CPtr: + """在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None""" + if name is None or _global_funcs is None: + return None + entry_size: t.CSizeT = FuncEntry.__sizeof__() + for i in range(_global_func_count): + entry_addr: t.CUInt64T = t.CUInt64T(_global_funcs) + i * entry_size + entry: FuncEntry | t.CPtr = (FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + return None + + # ============================================================ # 全局默认参数注册表(跨模块默认参数填充) # @@ -5705,9 +5824,15 @@ GLOBAL_DEFAULTS_MAX: t.CDefine = 4096 class FuncDefaultsEntry: """默认参数表条目""" Name: str - Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]) + Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset) DefaultCount: int ParamCount: int # 形参数量(不含 self) + # 常量快照(stdlib 分配,跨文件永久存活): + # 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR, + # 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。 + ConstKinds: t.CInt | t.CPtr # const_kind 数组(DefaultCount 个 i32) + ConstInts: t.CInt64T | t.CPtr # int_val 数组(DefaultCount 个 i64) + ConstStrs: t.CSizeT | t.CPtr # str_val 指针数组(DefaultCount 个 i8*) _global_defaults: FuncDefaultsEntry | t.CPtr = None _global_defaults_count: int = 0 @@ -5730,7 +5855,11 @@ def _register_global_defaults(name: str, defaults: t.CVoid | t.CPtr, default_count: int, param_count: int) -> int: - """注册函数默认参数到全局表,返回 0 成功""" + """注册函数默认参数到全局表,返回 0 成功 + + 注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs), + 跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。 + """ global _global_defaults_count if name is None or defaults is None: return 1 @@ -5744,26 +5873,96 @@ def _register_global_defaults(name: str, entry_size: t.CSizeT = FuncDefaultsEntry.__sizeof__() entry_addr: t.CUInt64T = t.CUInt64T(_global_defaults) + _global_defaults_count * entry_size entry: FuncDefaultsEntry | t.CPtr = (FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - entry.Name = name + # Name 深拷贝到 stdlib(全局表跨文件永久存活) + nm_len: t.CSizeT = string.strlen(name) + nm_copy: t.CChar | t.CPtr = stdlib.malloc(nm_len + 1) + if nm_copy is None: + return 1 + string.strcpy(nm_copy, name) + entry.Name = nm_copy entry.Defaults = defaults entry.DefaultCount = default_count entry.ParamCount = param_count + # 提取常量快照到 stdlib + if default_count > 0: + kinds: t.CInt | t.CPtr = stdlib.malloc(default_count * 4) + ints: t.CInt64T | t.CPtr = stdlib.malloc(default_count * 8) + strs: t.CSizeT | t.CPtr = stdlib.malloc(default_count * 8) + if kinds is not None and ints is not None and strs is not None: + string.memset(kinds, 0, default_count * 4) + string.memset(ints, 0, default_count * 8) + string.memset(strs, 0, default_count * 8) + dl: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(defaults), t.CPtr)) + di: int + for di in range(default_count): + dnode: ast.AST | t.CPtr = dl.get(di) + if dnode is not None and dnode.kind() == ast.ASTKind.Constant: + dcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dnode) + kinds[di] = dcn.const_kind + ints[di] = dcn.int_val + if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None: + slen: t.CSizeT = string.strlen(dcn.str_val) + scopy: t.CChar | t.CPtr = stdlib.malloc(slen + 1) + if scopy is not None: + string.strcpy(scopy, dcn.str_val) + strs[di] = t.CSizeT(scopy) + entry.ConstKinds = kinds + entry.ConstInts = ints + entry.ConstStrs = strs _global_defaults_count += 1 return 0 -def find_func_defaults(name: str) -> FuncDefaultsEntry | t.CPtr: - """按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None""" - if name is None or _global_defaults is None: - return None - entry_size: t.CSizeT = FuncDefaultsEntry.__sizeof__() - i: int = 0 - while i < _global_defaults_count: - entry_addr: t.CUInt64T = t.CUInt64T(_global_defaults) + i * entry_size - entry: FuncDefaultsEntry | t.CPtr = (FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry - i += 1 +def find_func_defaults(name: str) -> FuncDefaultsEntry | t.CPtr: + """按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None""" + if name is None or _global_defaults is None: + return None + entry_size: t.CSizeT = FuncDefaultsEntry.__sizeof__() + i: int = 0 + while i < _global_defaults_count: + entry_addr: t.CUInt64T = t.CUInt64T(_global_defaults) + i * entry_size + entry: FuncDefaultsEntry | t.CPtr = (FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + i += 1 + return None + + +# _build_const_from_snapshot — 从常量快照重建常量 IR 值 +# +# 用于跨模块默认参数填充:gd_entry.Defaults(pool 内 AST)可能已被 reset 回收, +# 改用注册时提取的 stdlib 常量快照(ConstKinds/ConstInts/ConstStrs)重建常量 IR。 +# 返回 llvmlite.Value*,失败返回 None。 +def _build_const_from_snapshot(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + gd_entry: FuncDefaultsEntry | t.CPtr, + di: int, + trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr: + """从快照重建第 di 个默认值常量 IR""" + if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None: + return None + if di < 0 or di >= gd_entry.DefaultCount: + return None + kind: t.CInt = gd_entry.ConstKinds[di] + ival: t.CInt64T = gd_entry.ConstInts[di] + if kind == ast.CONST_INT: + if ival > 2147483647 or ival < -2147483648: + return llvmlite.const_int64(pool, ival) + return llvmlite.const_int32(pool, ival) + elif kind == ast.CONST_BOOL: + if ival != 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + elif kind == ast.CONST_NONE: + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + elif kind == ast.CONST_STR: + if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0: + sv: str = (str | t.CPtr)(t.CVoid(gd_entry.ConstStrs[di], t.CPtr)) + return HandlesExpr.create_global_string(builder, pool, mod, sv, trans) + # 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST return None def find_func_entry_in_table(funcs: FuncEntry | t.CPtr, diff --git a/App/lib/core/Handles/HandlesFunctions.vp b/App/lib/core/Handles/HandlesFunctions.vp index 168ceb4..45435ae 100644 --- a/App/lib/core/Handles/HandlesFunctions.vp +++ b/App/lib/core/Handles/HandlesFunctions.vp @@ -373,7 +373,8 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr, max_funcs: int = 256 cur_count: int = trans._func_count if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs, - fd_defaults, fd_default_count, fd_param_count) == 0: + fd_defaults, fd_default_count, fd_param_count, + trans.Pool) == 0: trans._func_count = cur_count + 1 # 注册 CExport 函数到全局表 @@ -410,6 +411,9 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr, if ags.vararg is not None: func.IsVarArg = 1 + # 参数添加完成,补全全局函数表的 TypeStr(供 vtable 在 func 被 reset 后使用) + HandlesExprCall.update_global_func_typestr(trans.Pool, fd.name, func) + return 0 @@ -497,7 +501,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr, # 注册到函数表 max_funcs_extern: int = 256 - if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern) == 0: + if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern, None, 0, 0, pool) == 0: trans._func_count = func_count + 1 # 添加参数(支持类型注解) @@ -530,6 +534,9 @@ def translate_function_def(trans: HT.Translator | t.CPtr, if func_attrs_e is not None: llvmlite.function_set_attrs(func, func_attrs_e) + # 参数添加完成,补全全局函数表的 TypeStr + HandlesExprCall.update_global_func_typestr(pool, fd.name, func) + return 0 # args_node 用于后续 alloca 创建,提前赋值 @@ -576,7 +583,8 @@ def translate_function_def(trans: HT.Translator | t.CPtr, # 注册到函数表 max_funcs: int = 256 if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs, - tfd_defaults, tfd_default_count, tfd_param_count) == 0: + tfd_defaults, tfd_default_count, tfd_param_count, + trans.Pool) == 0: trans._func_count = func_count + 1 # 添加参数(支持类型注解) @@ -607,6 +615,9 @@ def translate_function_def(trans: HT.Translator | t.CPtr, if ags.vararg is not None: func.IsVarArg = 1 + # 参数添加完成,补全全局函数表的 TypeStr + HandlesExprCall.update_global_func_typestr(trans.Pool, fd.name, func) + # 创建 entry 块 entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") if entry_blk is None: diff --git a/App/lib/core/Handles/HandlesMain.vp b/App/lib/core/Handles/HandlesMain.vp index 426bad6..89fae45 100644 --- a/App/lib/core/Handles/HandlesMain.vp +++ b/App/lib/core/Handles/HandlesMain.vp @@ -87,6 +87,12 @@ def translate_children(trans: HT.Translator | t.CPtr, child: ast.AST | t.CPtr = ch.get(ci) if child is None: continue kd: int = child.kind() + if kd == ast.ASTKind.ClassDef: + stdio.printf("[MAIN-DBG] module child[%d] kind=%d ClassDef\n", ci, kd) + elif kd == ast.ASTKind.FunctionDef: + stdio.printf("[MAIN-DBG] module child[%d] kind=%d FunctionDef\n", ci, kd) + elif kd == ast.ASTKind.AnnAssign: + stdio.printf("[MAIN-DBG] module child[%d] kind=%d AnnAssign\n", ci, kd) # _declare_only == 0 时,_translate_module_level 已预处理导入语句, # 此处跳过避免重复处理(from_imports 条目重复) diff --git a/App/lib/core/Handles/HandlesStruct.vp b/App/lib/core/Handles/HandlesStruct.vp index 0550934..e9a4016 100644 --- a/App/lib/core/Handles/HandlesStruct.vp +++ b/App/lib/core/Handles/HandlesStruct.vp @@ -66,6 +66,16 @@ class StructEntry: _struct_table: StructEntry | t.CPtr = None _struct_count: int = 0 +# OOM 回收标志:1=后续 register_struct/add_field 的新分配用 stdlib(跨文件永久存活), +# 0=用 pool(mark1 前阶段,会被保留)。Phase1 在 1b 开始前设为 1。 +_g_stdlib_alloc: int = 0 + + +def set_stdlib_alloc(flag: int): + """设置 OOM 回收分配模式:1=1b 阶段(新条目用 stdlib),0=注册阶段(用 pool)""" + global _g_stdlib_alloc + _g_stdlib_alloc = flag + # ============================================================ # 跨模块命名空间隔离:per-file 结构体可见性 @@ -193,10 +203,12 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr, return None # 用类型指针去重(同一类型不重复注册,支持跨模块同名类) + # 用 t.CUInt64T 指针值比较(is 比较会触发类型安全检查解引用悬空 Ty) + st_dedup: t.CUInt64T = t.CUInt64T(struct_ty) for i in range(_struct_count): existing: StructEntry | t.CPtr = _get_struct_entry(i) if existing is not None and existing.Ty is not None: - if existing.Ty is struct_ty: + if t.CUInt64T(existing.Ty) == st_dedup: return existing if _struct_count >= STRUCT_MAX: @@ -210,16 +222,22 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr, if entry is None: return None - # 分配字段数组 + # 分配字段数组(1b 阶段用 stdlib,避免 reset 回收后 Fields 悬空) field_size: t.CSizeT = FieldEntry.__sizeof__() - entry.Fields = pool.alloc(field_size * FIELD_MAX) + if _g_stdlib_alloc != 0: + entry.Fields = stdlib.malloc(field_size * FIELD_MAX) + else: + entry.Fields = pool.alloc(field_size * FIELD_MAX) if entry.Fields is None: return None string.memset(entry.Fields, 0, field_size * FIELD_MAX) - # 复制类名 + # 复制类名(1b 阶段用 stdlib) name_len: t.CSizeT = string.strlen(name) - name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) + if _g_stdlib_alloc != 0: + name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1) + else: + name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) if name_buf is not None: string.strcpy(name_buf, name) entry.Name = name_buf @@ -230,7 +248,10 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr, # 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry) if sha1 is not None: sha1_len: t.CSizeT = string.strlen(sha1) - sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1) + if _g_stdlib_alloc != 0: + sha1_buf: t.CChar | t.CPtr = stdlib.malloc(sha1_len + 1) + else: + sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1) if sha1_buf is not None: string.strcpy(sha1_buf, sha1) entry.ModuleSha1 = sha1_buf @@ -308,9 +329,12 @@ def add_field(pool: memhub.MemBuddy | t.CPtr, if fe is None: return -1 - # 复制字段名 + # 复制字段名(1b 阶段用 stdlib,避免 reset 回收后 fe.Name 悬空) name_len: t.CSizeT = string.strlen(field_name) - name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) + if _g_stdlib_alloc != 0: + name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1) + else: + name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) if name_buf is not None: string.strcpy(name_buf, field_name) fe.Name = name_buf @@ -399,13 +423,20 @@ def find_struct_by_module(name: str, sha1: str) -> StructEntry | t.CPtr: # 直接用指针身份定位 entry,规避跨模块同名类 find_struct 找错的问题。 # ============================================================ def find_struct_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> StructEntry | t.CPtr: - """按类型指针查找结构体(is 比较),返回 StructEntry 或 None""" + """按类型指针查找结构体(指针值比较),返回 StructEntry 或 None + + 注意: 不能用 `entry.Ty is struct_ty` 的 is 比较——TPV 编译 is 时会触发 + translate_compare 的类型安全检查(is_ptr_type/TypePrint 递归打印), + 对悬空 entry.Ty(1b 泛型特化类注册后被 reset 回收的 pool 指针)解引用崩溃。 + 改用 t.CUInt64T 纯指针值比较,不解引用任何内容。 + """ if struct_ty is None or _struct_table is None: return None + st_val: t.CUInt64T = t.CUInt64T(struct_ty) for i in range(_struct_count): entry: StructEntry | t.CPtr = _get_struct_entry(i) if entry is not None and entry.Ty is not None: - if entry.Ty is struct_ty: + if t.CUInt64T(entry.Ty) == st_val: return entry return None @@ -436,11 +467,12 @@ def lookup_field(struct_ty: llvmlite.LLVMType | t.CPtr, # - 名称匹配但字段未找到时 continue(继续检查其他同名 entry) # ============================================================ - # 第一遍: is 身份比较 + # 第一遍: is 身份比较(用 t.CUInt64T 指针值比较,避免 is 编译路径解引用悬空 Ty) + st_lk: t.CUInt64T = t.CUInt64T(struct_ty) for i in range(_struct_count): entry: StructEntry | t.CPtr = _get_struct_entry(i) if entry is not None and entry.Ty is not None: - if entry.Ty is struct_ty: + if t.CUInt64T(entry.Ty) == st_lk: # is 匹配,查找字段 for fi in range(entry.FieldCount): fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi) @@ -666,11 +698,12 @@ def is_union_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> int: if struct_ty is None or _struct_table is None: return 0 ty_name: str = _extract_struct_name(struct_ty) + st_iu: t.CUInt64T = t.CUInt64T(struct_ty) for i in range(_struct_count): entry: StructEntry | t.CPtr = _get_struct_entry(i) if entry is not None and entry.Ty is not None: matched: int = 0 - if entry.Ty is struct_ty: + if t.CUInt64T(entry.Ty) == st_iu: matched = 1 elif ty_name is not None and entry.Name is not None: if string.strcmp(entry.Name, ty_name) == 0: @@ -778,10 +811,11 @@ def get_class_name_by_type(pool: memhub.MemBuddy | t.CPtr, """按类型指针查找类名,返回类名字符串或 None""" if struct_ty is None or _struct_table is None: return None + st_cn: t.CUInt64T = t.CUInt64T(struct_ty) for i in range(_struct_count): entry: StructEntry | t.CPtr = _get_struct_entry(i) if entry is not None and entry.Ty is not None: - if entry.Ty is struct_ty: + if t.CUInt64T(entry.Ty) == st_cn: return entry.Name # 回退: 类型指针比较失败时,遍历所有注册的结构体按名称匹配 # 提取 struct_ty 的 Name 字段(可能是 "SHA1.ClassName" 格式) diff --git a/App/lib/core/Handles/HandlesTranslator.vp b/App/lib/core/Handles/HandlesTranslator.vp index bc8cfc7..e6ce074 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Handles/HandlesTranslator.vp @@ -232,10 +232,16 @@ class Translator: pool: memhub.MemBuddy | t.CPtr = _mbuddy # 初始化状态 + stdio.printf("[TRDBG] translate enter, declare_only=%d\n", self._declare_only) + stdio.fflush(None) self._init_state(pool) + stdio.printf("[TRDBG] after _init_state, funcs=%p\n", self._funcs) + stdio.fflush(None) # 创建 LLVM 模块 mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main") + stdio.printf("[TRDBG] after new_module, mod=%p\n", mod) + stdio.fflush(None) if mod is None: VLogger.error("NewModule returned NULL", "TR") return 1 @@ -246,15 +252,21 @@ class Translator: if triple is None: triple = "x86_64-pc-windows-msvc" llvmlite.module_set_target(mod, triple) + stdio.printf("[TRDBG] after module_set_target\n") + stdio.fflush(None) # 类型 i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + stdio.printf("[TRDBG] after types i32=%p i8=%p i8ptr=%p\n", i32_ty, i8_ty, i8_ptr_ty) + stdio.fflush(None) # 声明 printf printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( pool, mod, "printf", i32_ty) + stdio.printf("[TRDBG] after create_declare printf=%p\n", printf_func) + stdio.fflush(None) if printf_func is None: VLogger.error("CreateDeclare printf returned NULL", "TR") return 1 @@ -273,6 +285,8 @@ class Translator: pool, mod, "llvm.va_end", void_ty_decl) if va_end_func is not None: llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap") + stdio.printf("[TRDBG] after va_start/va_end decl\n") + stdio.fflush(None) # 声明 malloc(闭包分配用) malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( @@ -280,12 +294,18 @@ class Translator: if malloc_func is not None: i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) llvmlite.add_param(pool, malloc_func, i64_ty, "size") + stdio.printf("[TRDBG] after malloc decl\n") + stdio.fflush(None) # 检查用户是否定义了 main 函数 has_user_main: int = 0 ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + stdio.printf("[TRDBG] tree.children=%p\n", ch) + stdio.fflush(None) if ch is not None: cn_count: t.CSizeT = ch.__len__() + stdio.printf("[TRDBG] children count=%d\n", cn_count) + stdio.fflush(None) for ci in range(cn_count): child: ast.AST | t.CPtr = ch.get(ci) if child is not None and child.kind() == ast.ASTKind.FunctionDef: @@ -294,6 +314,8 @@ class Translator: if string.strcmp(fd.name, "main") == 0: has_user_main = 1 break + stdio.printf("[TRDBG] main check done, has_user_main=%d\n", has_user_main) + stdio.fflush(None) if self._declare_only != 0: # Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder @@ -343,9 +365,13 @@ class Translator: elif kd == ast.ASTKind.ImportFrom: self.ImportsH.HandleImportFromModule(child) self.ImportsH.HandleImportFromNames(child) + stdio.printf("[MLDBG] after import preprocess\n") + stdio.fflush(None) # 扫描当前模块的 CTypedef 声明(NAME: t.CTypedef = Type), # 注册到动态 CTypedef 表,供 resolve_annotation_type 查询 HandlesType.ScanCTypedefDeclarations(pool, tree) + stdio.printf("[MLDBG] after ScanCTypedefDeclarations\n") + stdio.fflush(None) # 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件, # 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题 # 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁) @@ -354,6 +380,8 @@ class Translator: StubMerger.LoadDepVpiIntoModule( pool, mod, self._imported_modules, self._from_imports, HandlesExprCall._g_temp_dir, self) + stdio.printf("[MLDBG] after LoadDepVpiIntoModule\n") + stdio.fflush(None) # 预注册模块级变量(AnnAssign/Assign)到 SymTab # 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时, # _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后, @@ -369,9 +397,15 @@ class Translator: kd_mv: int = child.kind() if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign: HandlesMain.handle_module_level_var(self, child) + stdio.printf("[MLDBG] after module-level var pre-reg\n") + stdio.fflush(None) # 创建前向声明 HandlesFunctions.forward_declare_functions(self, tree) + stdio.printf("[MLDBG] after forward_declare_functions\n") + stdio.fflush(None) added: int = HandlesMain.translate_children(self, tree) + stdio.printf("[MLDBG] after translate_children\n") + stdio.fflush(None) # ============================================================ # IR 输出 diff --git a/App/lib/core/IncludesScanner.vp b/App/lib/core/IncludesScanner.vp index bf588b7..6b9ebab 100644 --- a/App/lib/core/IncludesScanner.vp +++ b/App/lib/core/IncludesScanner.vp @@ -172,6 +172,7 @@ def compute_file_sha1(pool: memhub.MemBuddy | t.CPtr, bytes_read: t.CInt64T = f.read_all(buf, BUF_SIZE) f.close() if bytes_read <= 0: + stdlib.free(buf) return None # 原地去除 \r(CRLF → LF),与 Projectrans.py 文本模式读取一致 @@ -190,17 +191,21 @@ def compute_file_sha1(pool: memhub.MemBuddy | t.CPtr, # 计算 SHA1 ctx: hashlib.sha1 | t.CPtr = hashlib.sha1() if ctx is None: + stdlib.free(buf) return None ctx.update(buf) digest: bytes = stdlib.malloc(hashlib.SHA1_DIGEST_LEN) if digest is None: + stdlib.free(buf) return None ctx.final(digest) # 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符) hex_buf: str = stdlib.malloc(17) if hex_buf is None: + stdlib.free(buf) + stdlib.free(digest) return None for i in range(8): hi: int = (digest[i] >> 4) & 0xF @@ -214,6 +219,8 @@ def compute_file_sha1(pool: memhub.MemBuddy | t.CPtr, else: hex_buf[i * 2 + 1] = 'a' + (lo - 10) hex_buf[16] = '\0' + stdlib.free(buf) + stdlib.free(digest) return hex_buf diff --git a/App/lib/core/Phase1.vp b/App/lib/core/Phase1.vp index 9dc02ea..091fb01 100644 --- a/App/lib/core/Phase1.vp +++ b/App/lib/core/Phase1.vp @@ -546,6 +546,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # 初始化 AST 表(只需一次) ast._init_tables(mb) + stdio.printf("[MEM-DBG] 扫描完成后: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) # FileEntry 结构体大小(Phase 1a 和 1b 共用) entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() @@ -561,6 +563,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, p1a_skipped: int = 0 p1a_failed: int = 0 + stdio.printf("[MEM-DBG] Phase 1a-pre 扫描 import 前: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) + for i in range(result.Count): entry_addr_a: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size entry_a: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_a, t.CPtr)) @@ -577,6 +582,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, p1a_skipped += 1 continue + stdio.printf("[MEM-DBG] Phase 1a-pre 翻译前: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) + # 读取文件内容 file_path_a: str = entry_a.Path f_a: fileio.File | t.CPtr = fileio.File(file_path_a, fileio.MODE.R) @@ -660,6 +668,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, stdlib.free(src_buf_a) + stdio.printf("[MEM-DBG] Phase 1a-pre 扫描 import 完成: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) + # ============================================================ # 依赖图按需翻译:构建可达 SHA1 集合 # @@ -776,6 +787,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, viperlib.snprintf(fb_gpre, 1024, "预注册 %d 个泛型类模板文件", generic_file_count) VLogger.info(fb_gpre, "Phase1") + stdio.printf("[MEM-DBG] 泛型模板预注册前: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) + for gi in range(generic_file_count): gi_addr_p: t.CUInt64T = t.CUInt64T(generic_file_indices) + gi * 4 gi_ptr_p: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(gi_addr_p, t.CPtr)) @@ -839,6 +853,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, stdlib.free(gen_tr._nonlocal_names) stdlib.free(gen_src) + stdio.printf("[MEM-DBG] 泛型模板预注册完成: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) + # 遍历文件:优先使用拓扑顺序,回退到字母序 iter_count: int = topo_count if topo_count > 0 else result.Count for i in range(iter_count): @@ -924,6 +941,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, HandlesType.clear_cdefine_constants() HandlesType.clear_ctypedefs() HandlesStruct.reset_visible_structs(mb, 0) + stdio.printf("[MEM-DBG] Phase 1a struct 注册前: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) ret_r: int = tr_r.translate(tree_r) if ret_r != 0: p1a_fl += 1 @@ -956,6 +975,18 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # ============================================================ # Phase 1b: 全量翻译(struct 已注册,走 existing 路径翻译方法体) # ============================================================ + # OOM 回收:1a-pre/泛型预注册/1a 全部结束后打 mark1, + # 所有跨文件持久表(_struct_table/_enum_table/_generic_class_nodes/ + # _renum_*/关键字表等)都落在 mark1 之前。 + # 1b 每文件翻译完后 reset_to(mark1) 回收该文件的 AST/IR/Handler/dump 临时, + # 避免 90 文件累积导致 1GB 池 OOM。 + mark1: t.CSizeT = mb.mark() + stdio.printf("[MEM-DBG] Phase 1b 打点 mark1=%zu: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mark1, mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) + + # 1b 阶段新注册的 struct/enum 条目改 stdlib 分配(跨文件永久存活,不被 reset 回收) + HandlesStruct.set_stdlib_alloc(1) + # 遍历每个文件 translated: int = 0 skipped: int = 0 @@ -1020,7 +1051,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, viperlib.snprintf(fb, 1024, "翻译: %s (sha1=%s)", rp, sha1) VLogger.info(fb, "Phase1") + stdio.printf("[MEM-DBG] Phase 1b 翻译前: total=%zu used=%zu free=%zu free_blocks=%zu\n", + mb.usable_size, mb.used_bytes(), mb.free_bytes(), mb.free_count()) + + stdio.printf("[STDBG] stepA before free(stub_path)\n") + stdio.fflush(None) stdlib.free(stub_path) + stdio.printf("[STDBG] stepB after free(stub_path)\n") + stdio.fflush(None) # 读取文件内容 file_path: str = entry.Path @@ -1060,6 +1098,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, src_buf[bytes_read] = 0 else: src_buf[SRC_BUF_SIZE - 1] = 0 + stdio.printf("[STDBG] stepC after file read, bytes_read=%d\n", bytes_read) + stdio.fflush(None) # 解析 AST lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) @@ -1068,8 +1108,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, failed += 1 continue ast._lexer_init(lx, src_buf, mb) + stdio.printf("[STDBG] stepD before tokenize\n") + stdio.fflush(None) tokens: ast.Token | t.CPtr = ast.tokenize(lx) + stdio.printf("[STDBG] stepE after tokenize\n") + stdio.fflush(None) tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + stdio.printf("[STDBG] stepF after parse_tokens, tree=%p\n", tree) + stdio.fflush(None) if tree is None: fb: t.CChar | t.CPtr = VLogger.fmt_buf() if fb is not None: @@ -1083,6 +1129,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE) if pyi_buf is not None: pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, PYI_BUF_SIZE) + stdio.printf("[STDBG] stepG after _GeneratePyiFromAst, pyi_pos=%d\n", pyi_pos) + stdio.fflush(None) if pyi_pos > 0: pyi_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "vpi") if pyi_path is not None: @@ -1106,7 +1154,11 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, HandlesType.clear_cdefine_constants() HandlesType.clear_ctypedefs() HandlesStruct.reset_visible_structs(mb, 0) + stdio.printf("[STDBG] stepH before tr.translate\n") + stdio.fflush(None) ret: int = tr.translate(tree) + stdio.printf("[STDBG] stepI after tr.translate, ret=%d\n", ret) + stdio.fflush(None) if ret != 0: fb: t.CChar | t.CPtr = VLogger.fmt_buf() if fb is not None: @@ -1133,6 +1185,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, continue tr.dump_ir(stub_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_STUB) stub_len: t.CSizeT = string.strlen(stub_buf) + stdio.printf("[MEM-DBG] Phase 1b dump_ir(stub) done, len=%d used=%zu\n", + stub_len, mb.used_bytes()) # save stub.ll dir_len_p1: t.CSizeT = string.strlen(temp_dir) @@ -1157,6 +1211,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, continue tr.dump_ir(text_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_TEXT) text_len: t.CSizeT = string.strlen(text_buf) + stdio.printf("[MEM-DBG] Phase 1b dump_ir(text) done, len=%d used=%zu\n", + text_len, mb.used_bytes()) # save text.ll text_path_p1: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "text.ll") @@ -1190,6 +1246,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, translated += 1 + # OOM 回收:回收本文件翻译产生的瞬时数据(AST/tokens/lexer/IR/Handler/dump 临时) + # 持久表(struct/enum/REnum/spec 缓存/全局函数名等)已迁出 reset 区间(stdlib), + # reset_to(mark1) 只回收 mark1 之后分配、未被单独 free 的块。 + stdio.printf("[MEM-DBG] Phase 1b 翻译后 reset 前: used=%zu\n", mb.used_bytes()) + mb.reset_to(mark1) + stdio.printf("[MEM-DBG] Phase 1b reset 完成: used=%zu\n", mb.used_bytes()) + fb: t.CChar | t.CPtr = VLogger.fmt_buf() if fb is not None: viperlib.snprintf(fb, 1024, "完成: 翻译=%d 跳过=%d 失败=%d", translated, skipped, failed) diff --git a/App/lib/core/Phase2.vp b/App/lib/core/Phase2.vp index 70d0909..bc65600 100644 --- a/App/lib/core/Phase2.vp +++ b/App/lib/core/Phase2.vp @@ -177,6 +177,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, return 1 # === 栈金丝雀检查(全局变量,不影响栈布局)=== + global _g_canary _g_canary = 305419896 fb: t.CChar | t.CPtr = VLogger.fmt_buf()