From f8436c74d2b9a3c42b42b3bf1897173d461f90d8 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 6 Aug 2026 18:08:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=96=B0=E7=9A=84=E5=BB=BA?= =?UTF-8?q?=E8=AE=AE=E5=BF=BD=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 + App/lib/Projectrans/Config.vp | 95 ++++- App/lib/StubGen/VpiReader.vp | 5 + App/lib/core/BuildPipeline.vp | 2 + App/lib/core/Handles/HandlesAssign.vp | 5 + App/lib/core/Handles/HandlesBody.vp | 35 ++ App/lib/core/Handles/HandlesClassDef.vp | 478 ++++++++++++++-------- App/lib/core/Handles/HandlesExpr.vp | 33 ++ App/lib/core/Handles/HandlesExprCall.vp | 342 ++++++++++++++++ App/lib/core/Handles/HandlesImports.vp | 90 ++++ App/lib/core/Handles/HandlesMain.vp | 6 - App/lib/core/Handles/HandlesTranslator.vp | 34 -- App/lib/core/Handles/HandlesType.vp | 93 ++++- App/lib/core/Phase1.vp | 52 +-- 14 files changed, 1004 insertions(+), 271 deletions(-) diff --git a/.gitignore b/.gitignore index 16c5449..4e2cc21 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,8 @@ __pycache__/ *.swp *.swo *~ + +# 编译 +**/output/ +**/temp/ +**/.tpv_build/ \ No newline at end of file diff --git a/App/lib/Projectrans/Config.vp b/App/lib/Projectrans/Config.vp index 7322da9..5a10f36 100644 --- a/App/lib/Projectrans/Config.vp +++ b/App/lib/Projectrans/Config.vp @@ -220,6 +220,9 @@ def _join_path(rel: str, project_dir: str) -> str: - ../includes + Test → Test/../includes(OS 解析为 includes) - 绝对路径保持不变 - None 返回 None + + 拼接结果经 _normalize_path 规范化:./Test/../includes → ./includes, + 消除 .. 段,保证路径显示干净且相对寻址正确。 """ if rel is None: return None @@ -240,7 +243,7 @@ def _join_path(rel: str, project_dir: str) -> str: if buf is None: return rel viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel) - return buf + return _normalize_path(buf) # 处理 ./ 或 .\\ 前缀:拼接 project_dir + rel[2:] rel_off: t.CSizeT = 0 @@ -261,7 +264,95 @@ def _join_path(rel: str, project_dir: str) -> str: if buf is None: return rel # 分配失败,返回原路径 viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel + rel_off) - return buf + return _normalize_path(buf) + + +def _normalize_path(path: str) -> str: + """规范化路径:解析 . 和 .. 段,合并多余分隔符 + + 例: ./test/BuddyTest/../../includes → ./includes + ./test/BuddyTest/App → ./test/BuddyTest/App + 绝对路径(/ 或 \\ 开头,含盘符 C:)保持不变。 + 返回 _mbuddy 分配的字符串;失败时返回原路径。 + """ + if path is None: + return None + plen: t.CSizeT = string.strlen(path) + if plen == 0: + return path + # 绝对路径(/ 或 \ 开头,或盘符如 C:)不规范化 + if path[0] == '/' or path[0] == '\\': + return path + if plen >= 2 and path[1] == ':': + return path + # 输出缓冲(最坏情况 = 输入长度 + 可能的前缀 ./) + out: str = _mbuddy.alloc(plen + 3) + if out is None: + return path + seg_start: t.CSizeT = 0 + out_len: t.CSizeT = 0 + has_seg: int = 0 + i: t.CSizeT = 0 + while i <= plen: + ch: t.CChar = '\0' + if i < plen: + ch = path[i] + if ch == '/' or ch == '\\' or ch == '\0': + seg_len: t.CSizeT = i - seg_start + if seg_len > 0: + # 单段 ".":跳过 + if seg_len == 1 and path[seg_start] == '.': + pass + # 单段 "..":弹出上一段(无段可弹时保留,如 ../includes) + elif seg_len == 2 and path[seg_start] == '.' and path[seg_start + 1] == '.': + if out_len > 0: + # 回退到上一个分隔符 + k: t.CSizeT = out_len + while k > 0 and out[k - 1] != '/' and out[k - 1] != '\\': + k -= 1 + if k > 0: + out_len = k - 1 + else: + out_len = 0 + # 仍有剩余段时保持分隔符逻辑 + if out_len > 0: + has_seg = 1 + else: + has_seg = 0 + else: + # 无段可弹:保留 .. + out[0] = '.' + out[1] = '.' + out_len = 2 + has_seg = 1 + else: + # 普通段:追加分隔符 + 段 + if has_seg > 0: + out[out_len] = '/' + out_len += 1 + jj: t.CSizeT = 0 + while jj < seg_len: + out[out_len] = path[seg_start + jj] + out_len += 1 + jj += 1 + has_seg = 1 + seg_start = i + 1 + i += 1 + if has_seg == 0: + # 全部段被消掉(如 ./..):返回当前目录 + return "./" + # 相对路径补回 ./ 前缀(与原路径风格一致;以 .. 开头的除外) + if out[0] != '.' and out[0] != '/': + # 右移 2 位留出 "./"(从后往前拷贝,避免覆盖源字符) + mv: t.CSizeT = out_len + while mv > 0: + mv -= 1 + out[mv + 2] = out[mv] + out[0] = '.' + out[1] = '/' + out_len += 2 + out[out_len] = '\0' + return out def resolve_paths(project_dir: str) -> int: diff --git a/App/lib/StubGen/VpiReader.vp b/App/lib/StubGen/VpiReader.vp index 978be78..18d6ff0 100644 --- a/App/lib/StubGen/VpiReader.vp +++ b/App/lib/StubGen/VpiReader.vp @@ -348,6 +348,11 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr, if resolved_ty is not None: param_ty = resolved_ty llvmlite.add_param(pool, func, param_ty, pname) + # *args 变长参数:标记 IsVarArg=1,使调用侧走 C ABI 参数提升 + # (i8/i16 → i32,float → double),避免 %d/%x 等格式因参数按 i64 + # 传递而读错(第二个 %x 读到第一个 i64 槽的高 4 字节)。 + if args_node.vararg is not None: + func.IsVarArg = 1 # 注册到函数表(用裸名 fd.name,不是 mangled_name) if funcs_ptr is not None: diff --git a/App/lib/core/BuildPipeline.vp b/App/lib/core/BuildPipeline.vp index 9e1ecae..a91876d 100644 --- a/App/lib/core/BuildPipeline.vp +++ b/App/lib/core/BuildPipeline.vp @@ -119,6 +119,8 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, tr._declare_only = declare_only # 设置当前文件名(供报错使用) HandlesType.set_current_file(file_path) + # 同步到 HandlesImports(import 时 SHA1 检查报错需要当前文件名,循环依赖无法直接读 HandlesType) + HandlesImports.set_current_file(file_path) # 清空调用栈(每个文件翻译开始前重置) HandlesType.clear_trace() # 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离 diff --git a/App/lib/core/Handles/HandlesAssign.vp b/App/lib/core/Handles/HandlesAssign.vp index 61a1169..76bfcfd 100644 --- a/App/lib/core/Handles/HandlesAssign.vp +++ b/App/lib/core/Handles/HandlesAssign.vp @@ -292,6 +292,11 @@ class AssignHandle(HandlesBase.Mixin): # Attribute 赋值: obj.field = val if tk == ast.ASTKind.Attribute: + # property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时, + # 生成 call Class.attr$set(obj, v),跳过字段存储 + if HandlesExprCall._try_property_setter( + builder, pool, mod, target, rhs_val, self.Trans) == 1: + continue field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( builder, pool, mod, target, self.Trans) if field_ptr is not None: diff --git a/App/lib/core/Handles/HandlesBody.vp b/App/lib/core/Handles/HandlesBody.vp index c51572b..d674a4f 100644 --- a/App/lib/core/Handles/HandlesBody.vp +++ b/App/lib/core/Handles/HandlesBody.vp @@ -70,6 +70,41 @@ def translate_stmt(trans: HT.Translator | t.CPtr, return translate_continue(trans) elif k == ast.ASTKind.Match: return trans.MatchH.Handle(node) + elif k == ast.ASTKind.Delete: + return translate_delete(trans, node) + return 0 + + +# ============================================================ +# 翻译 Delete 语句: del obj.attr +# +# 支持 property deleter: 当目标 attr 是 @x.deleter 方法时, +# 生成 call Class.attr$del(obj)。其余目标暂不生成代码。 +# ============================================================ +def translate_delete(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 del 语句,返回 0""" + if trans is None or node is None: + return 0 + dnode: ast.Delete | t.CPtr = (ast.Delete | t.CPtr)(node) + if dnode is None or dnode.targets is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + if pool is None or mod is None or builder is None: + return 0 + tn: t.CSizeT = dnode.targets.__len__() + for ti in range(tn): + tgt: ast.AST | t.CPtr = dnode.targets.get(ti) + if tgt is None: + continue + # del obj.attr → property deleter + if tgt.kind() == ast.ASTKind.Attribute: + del_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tgt) + if del_at is not None: + HandlesExprCall._try_property_deleter( + pool, builder, mod, del_at, trans) return 0 diff --git a/App/lib/core/Handles/HandlesClassDef.vp b/App/lib/core/Handles/HandlesClassDef.vp index fed8d06..13e2c0a 100644 --- a/App/lib/core/Handles/HandlesClassDef.vp +++ b/App/lib/core/Handles/HandlesClassDef.vp @@ -224,6 +224,157 @@ def _has_decorator(decorator_list: list[ast.AST | t.CPtr] | t.CPtr, return 0 +# ============================================================ +# 方法元数据(装饰器)支持 +# +# 与 TPC 的 FuncMeta 对齐,按位掩码存储: +# META_STATIC @staticmethod 无 self 参数 +# META_CLASS @classmethod cls 为首参(Ptr(struct_ty)) +# META_PROP_GETTER @property / @x.getter obj.prop → call Class.prop(obj) +# META_PROP_SETTER @x.setter obj.prop = v → call Class.prop$set(obj, v) +# META_PROP_DELETER @x.deleter del obj.prop → call Class.prop$del(obj) +# +# setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突(与 TPC 一致)。 +# 元数据表用 stdlib 全局分配,跨模块持久(属性访问可能发生在其他模块)。 +# 注册时机:_translate_oop_methods(含 mark_only=1 的 struct 预注册阶段), +# 确保在 App 源文件翻译前元数据已就绪(不依赖 includes 是否已全量翻译)。 +# ============================================================ +META_STATIC: t.CDefine = 1 +META_CLASS: t.CDefine = 2 +META_PROP_GETTER: t.CDefine = 4 +META_PROP_SETTER: t.CDefine = 8 +META_PROP_DELETER: t.CDefine = 16 + +META_MAX: t.CDefine = 512 +META_KEY_LEN: t.CDefine = 128 + +_g_method_meta_keys: bytes = None +_g_method_meta_flags: bytes = None +_g_method_meta_count: int = 0 + + +# ============================================================ +# _extract_func_meta — 从 decorator_list 提取方法元数据位掩码 +# +# 支持(与 TPC HandlesFunctions._ExtractFuncMeta 对齐): +# @staticmethod / @property / @classmethod(Name 形式) +# @property.setter / @x.setter / @x.getter / @x.deleter(Attribute 形式) +# ============================================================ +def _extract_func_meta(decorator_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: + """从装饰器列表提取元数据位掩码,返回 0=无装饰器元数据""" + meta: int = 0 + if decorator_list is None: + return meta + dn: t.CSizeT = decorator_list.__len__() + if dn == 0: + return meta + for di in range(dn): + deco: ast.AST | t.CPtr = decorator_list.get(di) + if deco is None: + continue + k: int = deco.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) + if nm.id is not None: + if string.strcmp(nm.id, "staticmethod") == 0: + meta |= META_STATIC + elif string.strcmp(nm.id, "property") == 0: + meta |= META_PROP_GETTER + elif string.strcmp(nm.id, "classmethod") == 0: + meta |= META_CLASS + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco) + if at.attr is not None and at.value is not None: + if at.value.kind() == ast.ASTKind.Name: + vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + is_prop_name: int = 0 + if vn.id is not None and string.strcmp(vn.id, "property") == 0: + is_prop_name = 1 + # @property.setter 或 @x.setter/getter/deleter 都识别 + if is_prop_name != 0 or string.strcmp(at.attr, "setter") == 0 \ + or string.strcmp(at.attr, "getter") == 0 or string.strcmp(at.attr, "deleter") == 0: + if string.strcmp(at.attr, "setter") == 0: + meta |= META_PROP_SETTER + elif string.strcmp(at.attr, "getter") == 0: + meta |= META_PROP_GETTER + elif string.strcmp(at.attr, "deleter") == 0: + meta |= META_PROP_DELETER + return meta + + +# ============================================================ +# register_method_meta — 注册方法元数据(ClassName.method → meta) +# +# 幂等:重复注册相同 key 时更新标志位。内存用 stdlib 全局分配。 +# ============================================================ +def register_method_meta(class_name: str, method_name: str, + meta: int) -> None: + """注册方法元数据(幂等)""" + global _g_method_meta_keys, _g_method_meta_flags, _g_method_meta_count + if class_name is None or method_name is None or meta == 0: + return + # 懒初始化 + if _g_method_meta_keys is None: + _g_method_meta_keys = stdlib.malloc(META_MAX * META_KEY_LEN) + _g_method_meta_flags = stdlib.malloc(META_MAX * 4) + if _g_method_meta_keys is None or _g_method_meta_flags is None: + return + string.memset(_g_method_meta_keys, 0, META_MAX * META_KEY_LEN) + string.memset(_g_method_meta_flags, 0, META_MAX * 4) + # 构造 key "ClassName.method" + cl_len: t.CSizeT = string.strlen(class_name) + mn_len: t.CSizeT = string.strlen(method_name) + key_buf: bytes = stdlib.malloc(cl_len + mn_len + 2) + if key_buf is None: + return + viperlib.snprintf(key_buf, cl_len + mn_len + 2, "%s.%s", class_name, method_name) + # 去重更新 + i: int + for i in range(_g_method_meta_count): + if string.strcmp(_g_method_meta_keys + i * META_KEY_LEN, key_buf) == 0: + flags_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( + t.CUInt64T(_g_method_meta_flags) + i * 4, t.CPtr)) + flags_ptr[0] = meta + stdlib.free(key_buf) + return + if _g_method_meta_count < META_MAX: + string.strcpy(_g_method_meta_keys + _g_method_meta_count * META_KEY_LEN, key_buf) + flags_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( + t.CUInt64T(_g_method_meta_flags) + _g_method_meta_count * 4, t.CPtr)) + flags_ptr2[0] = meta + _g_method_meta_count += 1 + stdlib.free(key_buf) + + +# ============================================================ +# lookup_method_meta — 查找方法元数据(ClassName.method → meta) +# +# 返回位掩码;未注册返回 0。跨模块持久,供属性访问/赋值/删除识别。 +# ============================================================ +def lookup_method_meta(class_name: str, method_name: str) -> int: + """查找方法元数据位掩码,返回 0=未注册或非装饰器方法""" + if class_name is None or method_name is None: + return 0 + if _g_method_meta_keys is None or _g_method_meta_count <= 0: + return 0 + cl_len: t.CSizeT = string.strlen(class_name) + mn_len: t.CSizeT = string.strlen(method_name) + key_buf: bytes = stdlib.malloc(cl_len + mn_len + 2) + if key_buf is None: + return 0 + viperlib.snprintf(key_buf, cl_len + mn_len + 2, "%s.%s", class_name, method_name) + found: int = 0 + i: int + for i in range(_g_method_meta_count): + if string.strcmp(_g_method_meta_keys + i * META_KEY_LEN, key_buf) == 0: + flags_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid( + t.CUInt64T(_g_method_meta_flags) + i * 4, t.CPtr)) + found = flags_ptr[0] + break + stdlib.free(key_buf) + return found + + # ============================================================ # _is_marker_base — 检查基类名是否为标记基类(非真实父类) # @@ -2261,9 +2412,6 @@ 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 @@ -2293,9 +2441,6 @@ 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 回退残留或注册不完整) @@ -2340,14 +2485,11 @@ 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: @@ -2373,11 +2515,7 @@ 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,收集字段信息 @@ -2756,9 +2894,6 @@ def _format_func_type_str(pool: memhub.MemBuddy | t.CPtr, if buf is None or func is None or buf_size == 0: 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) @@ -2767,8 +2902,6 @@ 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) @@ -2777,58 +2910,60 @@ def _format_func_type_str(pool: memhub.MemBuddy | t.CPtr, _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 -# _generate_vtable — 生成 VTable 全局变量 +# ============================================================ +# vtable 收集暂存区(模块级) # -# 1. 收集 class body 中所有 FunctionDef 作为虚方法 -# 2. 构造 VTable 类型 { i8*, i8*, ... } -# 3. 构造初始化字符串 { i8* bitcast (...), ... } -# 4. 创建全局变量 @"SHA1.ClassName.vtable" -# 5. 存储虚方法名列表到 StructEntry -def _generate_vtable(trans: HT.Translator | t.CPtr, - cd: ast.ClassDef | t.CPtr, - class_name: str) -> int: - """生成 VTable 全局变量""" +# _collect_vtable_methods 的收集结果,跨函数传递: +# - _translate_oop_methods 在翻译方法体之前先收集一次, +# 使方法体内的 self.虚方法 调用能查到 VTableMethods(虚分派依赖) +# - _generate_vtable 再收集一次,生成 vtable 全局变量 +# method_names_buf 是 stdlib 分配,存入 StructEntry.VTableMethods +# 后跨模块持久(不得迁入 mb 池 reset 区间)。 +# ============================================================ +_g_vt_full_names: t.CSizeT | t.CPtr = None +_g_vt_method_names: t.CSizeT | t.CPtr = None +_g_vt_parent_sha1s: t.CSizeT | t.CPtr = None +_g_vt_method_count: int = 0 + + +# ============================================================ +# _collect_vtable_methods — 收集类的虚方法信息 +# +# 1. 继承父类虚方法(父类方法排在子类方法之前,保持槽位顺序一致) +# 2. 收集当前类虚方法(跳过已继承的) +# +# 结果存入模块级暂存区(_g_vt_*),并设置 entry.VTableMethodCount / +# VTableMethods(stdlib 分配,供虚分派跨模块查询)。 +# +# 返回 1=有虚方法 / 0=无方法或失败 +# ============================================================ +def _collect_vtable_methods(trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + class_name: str) -> int: + """收集虚方法信息,设置 entry.VTableMethods/VTableMethodCount""" + global _g_vt_full_names, _g_vt_method_names, _g_vt_parent_sha1s, _g_vt_method_count if trans is None or cd is None or class_name is None: return 0 - # 懒导入 - import lib.core.Handles.HandlesFunctions as HandlesFunctions - import lib.core.Handles.HandlesExprCall as HandlesExprCall - 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 @@ -2871,10 +3006,6 @@ 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: @@ -2978,13 +3109,57 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, method_count += 1 + # 暂存结果(_generate_vtable 复用) + _g_vt_full_names = full_names_buf + _g_vt_method_names = method_names_buf + _g_vt_parent_sha1s = method_parent_sha1s + _g_vt_method_count = method_count + + # 设置 entry 元数据(虚分派查询用;必须在本类方法体翻译前就绪, + # 否则方法体内 self.虚方法 调用无法虚分派) + if vt_self_entry is not None and method_count > 0: + vt_self_entry.VTableMethodCount = method_count + vt_self_entry.VTableMethods = method_names_buf + if method_count == 0: - stdio.printf("[VTDBG-STEP] class=%s collect done, method_count=0 -> return\n", class_name) + return 0 + return 1 + + +# _generate_vtable — 生成 VTable 全局变量 +# +# 1. 收集 class body 中所有 FunctionDef 作为虚方法 +# 2. 构造 VTable 类型 { i8*, i8*, ... } +# 3. 构造初始化字符串 { i8* bitcast (...), ... } +# 4. 创建全局变量 @"SHA1.ClassName.vtable" +# 5. 存储虚方法名列表到 StructEntry +def _generate_vtable(trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + class_name: str) -> int: + """生成 VTable 全局变量""" + if trans is None or cd is None or class_name is None: return 0 + # 懒导入 + import lib.core.Handles.HandlesFunctions as HandlesFunctions + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 收集虚方法信息(继承父类 + 自身,结果存模块级暂存区 _g_vt_*) + # 同时设置 entry.VTableMethodCount/VTableMethods(虚分派查询用) + if _collect_vtable_methods(trans, cd, class_name) == 0: + return 0 + full_names_buf: t.CSizeT | t.CPtr = _g_vt_full_names + method_names_buf: t.CSizeT | t.CPtr = _g_vt_method_names + method_parent_sha1s: t.CSizeT | t.CPtr = _g_vt_parent_sha1s + method_count: int = _g_vt_method_count + # 重新获取 entry(后续存储 VTableMethods 用) + vt_self_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + class_name, trans.ModuleSha1) + # 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) @@ -3009,8 +3184,6 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, if init_buf is None: return 0 init_buf[0] = '\0' - 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): @@ -3058,8 +3231,6 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, 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) @@ -3080,14 +3251,9 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, if func_ty_buf is None: _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*) - 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, "* @") @@ -3099,13 +3265,8 @@ def _generate_vtable(trans: HT.Translator | t.CPtr, else: _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, 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) @@ -3113,16 +3274,10 @@ 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 @@ -3131,18 +3286,11 @@ 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 @@ -3189,7 +3337,7 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr, # 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错) oop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - # 第一遍:检测是否有方法,标记 OOP + # 第一遍:检测是否有方法,标记 OOP,并注册装饰器元数据 for ci in range(cn): stmt: ast.AST | t.CPtr = children.get(ci) if stmt is None: @@ -3202,6 +3350,12 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr, has_init = 1 if string.strcmp(fd_check.name, "__new__") == 0: has_new = 1 + # 注册装饰器元数据(@property/@staticmethod/@classmethod/@x.setter 等)。 + # 此处(含 mark_only=1 的 struct 预注册阶段)注册, + # 确保其他模块在 App 文件翻译时能识别属性访问。 + fd_meta: int = _extract_func_meta(fd_check.decorator_list) + if fd_meta != 0: + register_method_meta(class_name, fd_check.name, fd_meta) if has_method == 0: # 子类没有自己的方法,但可能继承了父类的虚方法 @@ -3229,6 +3383,16 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr, return 0 # 第二遍:翻译每个方法 + # 翻译方法体前先预注册 vtable 元数据(VTableMethods/VTableMethodCount)。 + # 根因:方法体翻译先于 _generate_vtable,若不预注册,方法体内的 + # self.虚方法 调用(如 MemManager.calloc 里的 self.alloc)读不到 + # VTableMethods,虚分派失败,被静态绑定到本类实现(基类 alloc 返回 + # None),导致 calloc 永远返回 NULL。 + oop_has_vt_pre: int = 0 + if oop_entry is not None: + oop_has_vt_pre = oop_entry.HasVTable + if oop_has_vt_pre == 1: + _collect_vtable_methods(trans, cd, class_name) for ci in range(cn): stmt: ast.AST | t.CPtr = children.get(ci) if stmt is None: @@ -3236,8 +3400,6 @@ 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) @@ -3257,7 +3419,6 @@ 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 @@ -3296,8 +3457,26 @@ 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) + + # 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter) + func_meta: int = _extract_func_meta(fd.decorator_list) + # property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突 + method_name_buf: t.CChar | t.CPtr = pool.alloc(128) + if method_name_buf is None: + return 0 + viperlib.snprintf(method_name_buf, 128, "%s", fd.name) + if func_meta & META_PROP_SETTER != 0: + string.strcat(method_name_buf, "$set") + elif func_meta & META_PROP_DELETER != 0: + string.strcat(method_name_buf, "$del") + method_name = method_name_buf + + is_static_m: int = 0 + is_class_m: int = 0 + if func_meta & META_STATIC != 0: + is_static_m = 1 + if func_meta & META_CLASS != 0: + is_class_m = 1 # 构建方法全名: ClassName.method_name full_name_buf: t.CChar | t.CPtr = pool.alloc(128) @@ -3335,7 +3514,8 @@ def _translate_method(trans: HT.Translator | t.CPtr, if func is None: return 0 - # 提取默认参数信息(方法的 args[0] 是 self,不含在 param_count 中) + # 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中; + # @staticmethod 无 self,param_count 为完整参数数) # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 md_defaults: t.CVoid | t.CPtr = None @@ -3346,7 +3526,10 @@ def _translate_method(trans: HT.Translator | t.CPtr, md_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(md_args_node) if md_ags.args is not None: md_alist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.args - md_param_count = md_alist.__len__() - 1 + if is_static_m != 0: + md_param_count = md_alist.__len__() + else: + md_param_count = md_alist.__len__() - 1 if md_ags.defaults is not None: md_dlist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.defaults md_defaults = md_dlist @@ -3359,17 +3542,32 @@ def _translate_method(trans: HT.Translator | t.CPtr, pool) == 0: trans._func_count = func_count + 1 - # 添加 self 参数(Ptr(struct_ty)) - llvmlite.add_param(pool, func, self_ptr_ty, "%self") + # 添加 self/cls 参数(Ptr(struct_ty));@staticmethod 无 self,跳过 + # @classmethod 的 cls 也用 Ptr(struct_ty),首参名取 args[0](如 cls) + if is_static_m == 0: + first_pname: str = "self" + if is_class_m != 0 and fd.args is not None: + fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args) + if fd_ags.args is not None and fd_ags.args.__len__() > 0: + fd_first_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fd_ags.args.get(0)) + if fd_first_arg is not None and fd_first_arg.arg is not None: + first_pname = fd_first_arg.arg + first_pname_buf: t.CChar | t.CPtr = pool.alloc(32) + if first_pname_buf is not None: + viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname) + llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf) - # 添加其他参数(支持类型注解,跳过索引 0 的 self 参数) + # 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls) args_node: ast.Arguments | t.CPtr = fd.args if args_node is not None: ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) if ags.args is not None: alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args an: t.CSizeT = alist.__len__() - for ai in range(1, an): + start_idx: int = 0 + if is_static_m == 0: + start_idx = 1 + for ai in range(start_idx, an): arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) if arg is not None and arg.arg is not None: param_ty: llvmlite.LLVMType | t.CPtr = i32_ty @@ -3400,24 +3598,41 @@ def _translate_method(trans: HT.Translator | t.CPtr, # 进入函数作用域 HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION) - # 为 self 创建 alloca 并 store(与其他参数一致) + # 为 self/cls 创建 alloca 并 store(与其他参数一致);@staticmethod 无 self,跳过 # 修复: 之前 self 注册为 SSA 值导致 translate_name_value 错误地 load 一次 # 将 Ptr(struct_ty) 变成 struct 值,引发变参函数 ABI 不匹配崩溃 - self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty) - if self_alloca is not None: - HandlesVar.define_var(trans.SymTab, "self", self_alloca) - # 设置 self 的类型注解类名(属性访问 lookup_field 回退查找用) - HandlesVar.set_var_annot_class_name(trans.SymTab, "self", class_name) - self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") - llvmlite.build_store(func_builder, self_val, self_alloca) + if is_static_m == 0: + self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty) + if self_alloca is not None: + self_var_name: str = "self" + self_ssa_name: str = "%self" + if is_class_m != 0 and args_node is not None: + cags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if cags.args is not None and cags.args.__len__() > 0: + cfirst: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(cags.args.get(0)) + if cfirst is not None and cfirst.arg is not None: + self_var_name = cfirst.arg + self_ssa_name_buf: t.CChar | t.CPtr = pool.alloc(32) + if self_ssa_name_buf is not None: + viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg) + self_ssa_name = self_ssa_name_buf + HandlesVar.define_var(trans.SymTab, self_var_name, self_alloca) + # 设置 self/cls 的类型注解类名(属性访问 lookup_field 回退查找用) + HandlesVar.set_var_annot_class_name(trans.SymTab, self_var_name, class_name) + self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, self_ssa_name) + llvmlite.build_store(func_builder, self_val, self_alloca) - # 为其他参数创建 alloca 并 store(与普通函数一致,跳过索引 0 的 self 参数) + # 为其他参数创建 alloca 并 store(与普通函数一致; + # @staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls 参数) if args_node is not None: ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) if ags2.args is not None: alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args an2: t.CSizeT = alist2.__len__() - for ai2 in range(1, an2): + start_idx2: int = 0 + if is_static_m == 0: + start_idx2 = 1 + for ai2 in range(start_idx2, an2): arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) if arg2 is not None and arg2.arg is not None: param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty @@ -3537,27 +3752,18 @@ 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) @@ -3565,82 +3771,50 @@ 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 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: @@ -3699,31 +3873,16 @@ 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) @@ -3734,7 +3893,6 @@ 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 c84ca82..142b8d5 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -262,6 +262,15 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, """ if val is None or target_ty is None: return val + # 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针) + # 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理 + match val.Ty: + case llvmlite.LLVMType.Func(_, _, _): + if is_ptr_type(target_ty) != 0: + return llvmlite.build_bitcast(builder, val, target_ty) + return val + case _: + pass # 整数转换 val_bits: int = get_llvm_type_bits(val.Ty) target_bits: int = get_llvm_type_bits(target_ty) @@ -1903,6 +1912,13 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr, load_ty = alloca.Ty.Pointee if load_ty is None: load_ty = llvmlite.Int32(pool) + # 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`): + # 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。 + # 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致 + # `ptrtoint %Struct ... to i64` 无效指令(llc invalid cast opcode)。 + match load_ty: + case llvmlite.LLVMType.Struct(_, _, _): + return alloca return llvmlite.build_load(builder, load_ty, alloca) # 模块别名检查:SymTab 查找失败后才检查 @@ -1912,6 +1928,15 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr, if HandlesImports.is_module_imported(trans._imported_modules, nm_id) != 0: return None + # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 + # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 + # (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 + if trans is not None and trans.Module is not None: + fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module( + trans.Module, nm_id) + if fn_ref is not None: + return fn_ref + # 所有查找路径均失败 # fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错 # 避免对 match/self/pool 等关键字和变量名误报 @@ -2839,6 +2864,14 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr, builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx) if alias_ptr is not None: return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr) + # property getter 回退: obj.attr 是 @property/@x.getter 方法时生成调用 + # (字段未找到时先尝试,避免报误导性的"字段未找到"错误) + if field_info is None and at.value is not None and trans is not None: + prop_cls_fb: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) + prop_val: llvmlite.Value | t.CPtr = HandlesExprCall._try_property_getter_attr( + pool, builder, mod, at, obj_ptr, trans, prop_cls_fb) + if prop_val is not None: + return prop_val # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 # 传递 SHA1 以区分跨模块同名类 if field_info is None: diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index fdbb888..7ede28e 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -2894,6 +2894,35 @@ def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr, total_count += 1 param_node = llvmlite.param_get_next(param_node) + # 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0) + # 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT), + # 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾, + # 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。 + if found_func is not None and head is not None: + pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + # 跳过 self 参数(索引 0) + if pc_param is not None: + pc_param = llvmlite.param_get_next(pc_param) + pc_node: llvmlite.Value | t.CPtr = head.Next + new_tail: llvmlite.Value | t.CPtr = head + if head is not None: + head.Next = None + while pc_node is not None: + pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next + coerced_pc: llvmlite.Value | t.CPtr = pc_node + if pc_param is not None: + pty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pc_param) + if pty_pc is not None: + c_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, pc_node, pty_pc, None) + if c_pc is not None: + coerced_pc = c_pc + pc_param = llvmlite.param_get_next(pc_param) + coerced_pc.Next = None + new_tail.Next = coerced_pc + new_tail = coerced_pc + pc_node = pc_next_save + # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 # 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错) if found_func is not None: @@ -2950,6 +2979,11 @@ def _ensure_method_declare(pool: memhub.MemBuddy | t.CPtr, if string.strcmp(existing.Name, call_name) == 0: # 已存在:仅当是 declare 且参数数量不足时追加缺失参数 if existing.IsDeclared == 1: + # 变长函数(*args,IsVarArg=1)不追加参数:多余实参由 + # 变参机制(...)承接,追加有类型参数会导致调用侧把变参 + # 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。 + if existing.IsVarArg == 1: + return # 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断) cur_count: int = 0 cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) @@ -3329,6 +3363,296 @@ def _LookupMethodRetTyFromTextLL(pool: memhub.MemBuddy | t.CPtr, return result_ty +# ============================================================ +# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 +# +# 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, +# 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() +# 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 +# ============================================================ + +# ============================================================ +# _translate_property_call — 翻译属性方法调用 +# +# 与 _translate_method_call 的调用名/返回类型解析逻辑一致: +# 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) +# 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 +# 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) +# +# call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) +# ============================================================ +def _translate_property_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + call_head: llvmlite.Value | t.CPtr, + call_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译属性/静态方法调用,返回 call 结果 Value""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + + # 构造查找名: ClassName.method_name + lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) + + # 查找函数(精确/后缀匹配) + found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) + + # 确定调用名 + call_name: str = lookup_name + if found_func is not None: + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # 未找到:用类所属模块的 SHA1 构造调用名 + cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name) + if cls_sha1_pc is not None: + mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2 + mangled_pc: str = pool.alloc(mlen_pc) + if mangled_pc is not None: + viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name) + call_name = mangled_pc + + # 确定返回类型 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if found_func is not None: + frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt is not None: + call_ret_ty = frt + else: + cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name) + looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL( + pool, cls_sha1_rt, class_name, method_name) + if looked_up_ty is not None: + call_ret_ty = looked_up_ty + else: + call_ret_ty = _infer_method_ret_ty(pool, method_name) + + # 确保 declare 存在,然后调用 + _ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count) + return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0) + + +# ============================================================ +# _resolve_obj_class_name — 解析对象表达式的类名(短名) +# +# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), +# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 +# 供属性访问/赋值/删除识别 property 时使用。 +# ============================================================ +def _resolve_obj_class_name(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + obj_node: ast.AST | t.CPtr) -> str: + """解析对象表达式的类名(短名),失败返回 None""" + if pool is None or trans is None or obj_node is None: + return None + if obj_node.kind() == ast.ASTKind.Name: + obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node) + if obj_nm.id is not None: + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, obj_nm.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + annot_val: str = var_entry.AnnotClassName + dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.') + if dot_ptr is not None: + return dot_ptr + 1 + return annot_val + return None + + +# ============================================================ +# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 +# +# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; +# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 +# ============================================================ +def _try_property_getter_attr(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + at_node: ast.Attribute | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr, + fallback_class_name: str = None) -> llvmlite.Value | t.CPtr: + """尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None + + fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。 + """ + if at_node is None or at_node.attr is None or obj_ptr is None or trans is None: + return None + class_name: str = _resolve_obj_class_name(pool, trans, at_node.value) + if class_name is None: + class_name = fallback_class_name + if class_name is None: + return None + meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr) + if meta & HandlesClassDef.META_PROP_GETTER == 0: + return None + # 单参数调用: obj → getter + llvmlite.value_set_next(obj_ptr, None) + return _translate_property_call( + pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans) + + +# ============================================================ +# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 +# +# 检查 obj 的类是否有 @x.setter 的 attr 方法; +# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 +# ============================================================ +def _try_property_setter(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + target_attr: ast.Attribute | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """尝试 property setter 赋值,返回 1=已处理(生成调用)""" + if pool is None or builder is None or mod is None or trans is None: + return 0 + if target_attr is None or target_attr.attr is None or rhs_val is None: + return 0 + class_name: str = _resolve_obj_class_name(pool, trans, target_attr.value) + if class_name is None: + return 0 + meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) + if meta & HandlesClassDef.META_PROP_SETTER == 0: + return 0 + # 翻译对象值(self 参数) + obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, target_attr.value, None, 0, trans) + if obj_val is None: + return 0 + # 构建参数链表: obj → rhs + llvmlite.value_set_next(obj_val, None) + llvmlite.value_set_next(rhs_val, None) + llvmlite.value_set_next(obj_val, rhs_val) + # setter 函数名带 $set 后缀 + setter_name_buf: t.CChar | t.CPtr = pool.alloc(128) + if setter_name_buf is None: + return 0 + viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr) + _translate_property_call(pool, builder, mod, class_name, + setter_name_buf, obj_val, 2, trans) + return 1 + + +# ============================================================ +# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 +# +# 检查 obj 的类是否有 @x.deleter 的 attr 方法; +# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 +# ============================================================ +def _try_property_deleter(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + target_attr: ast.Attribute | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """尝试 property deleter 删除,返回 1=已处理(生成调用)""" + if pool is None or builder is None or mod is None or trans is None: + return 0 + if target_attr is None or target_attr.attr is None: + return 0 + class_name: str = _resolve_obj_class_name(pool, trans, target_attr.value) + if class_name is None: + return 0 + meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) + if meta & HandlesClassDef.META_PROP_DELETER == 0: + return 0 + # 翻译对象值(self 参数) + obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, target_attr.value, None, 0, trans) + if obj_val is None: + return 0 + llvmlite.value_set_next(obj_val, None) + # deleter 函数名带 $del 后缀 + del_name_buf: t.CChar | t.CPtr = pool.alloc(128) + if del_name_buf is None: + return 0 + viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr) + _translate_property_call(pool, builder, mod, class_name, + del_name_buf, obj_val, 1, trans) + return 1 + + +# ============================================================ +# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 +# +# @staticmethod: 直接 call Class.method(args...),无 self +# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) +# ============================================================ +def _translate_static_class_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None""" + if pool is None or builder is None or mod is None or trans is None: + return None + if class_name is None or method_name is None or cl is None: + return None + meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name) + is_static: int = 0 + is_class: int = 0 + if meta & HandlesClassDef.META_STATIC != 0: + is_static = 1 + if meta & HandlesClassDef.META_CLASS != 0: + is_class = 1 + if is_static == 0 and is_class == 0: + return None + + # 构建参数链表 + head: llvmlite.Value | t.CPtr = None + total_count: int = 0 + + # @classmethod: 插入栈上分配的类实例指针作为 cls 参数 + if is_class != 0: + struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) + if struct_ty_cc is None: + return None + cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc) + if cls_ptr is None: + return None + llvmlite.value_set_next(cls_ptr, None) + head = cls_ptr + total_count = 1 + + # 翻译调用参数 + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = cargs.__len__() + tail: llvmlite.Value | t.CPtr = head + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is None: + continue + llvmlite.value_set_next(arg_val, None) + if head is None: + head = arg_val + tail = arg_val + else: + llvmlite.value_set_next(tail, arg_val) + tail = arg_val + total_count += 1 + + if head is None: + return None + + return _translate_property_call(pool, builder, mod, class_name, + method_name, head, total_count, trans) + + # ============================================================ # _translate_method_call - 翻译方法调用 obj.method(args) # @@ -4445,6 +4769,24 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr, i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) + # 检测类名静态/类方法调用: ClassName.method(args) + # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, + # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if st_at is not None and st_at.value is not None and trans is not None: + if st_at.value.kind() == ast.ASTKind.Name: + st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value) + if st_nm.id is not None: + # 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法 + st_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, st_nm.id) + if st_var is None and HandlesStruct.get_struct_type(st_nm.id) is not None: + st_res: llvmlite.Value | t.CPtr = _translate_static_class_call( + pool, builder, mod, st_nm.id, func_name, cl, trans) + if st_res is not None: + return st_res + # 检测方法调用: obj.method(args) # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: diff --git a/App/lib/core/Handles/HandlesImports.vp b/App/lib/core/Handles/HandlesImports.vp index 0a4f8a6..58f0185 100644 --- a/App/lib/core/Handles/HandlesImports.vp +++ b/App/lib/core/Handles/HandlesImports.vp @@ -6,9 +6,12 @@ import string import stdlib import viperlib import stdio +import sys +import lib.core.VLogger as VLogger import lib.core.Handles.HandlesBase as HandlesBase import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.StubMerger as StubMerger # ============================================================ @@ -468,6 +471,85 @@ def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr, return buf +# ============================================================ +# 全局当前文件名(镜像 HandlesType._g_current_file) +# +# HandlesImports 因循环依赖(HandlesType import 了本模块)不能 +# import HandlesType,无法读取其 _g_current_file。因此由 +# BuildPipeline/Phase1 在调用 HandlesType.set_current_file 时 +# 同步调用本模块的 set_current_file,供导入时 SHA1 检查报错使用。 +# ============================================================ +_g_current_file: str = None + + +def set_current_file(file_path: str) -> None: + """设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用)""" + global _g_current_file + _g_current_file = file_path + + +# ============================================================ +# _report_import_error - 本地实现 Python 风格报错(避免循环依赖) +# +# 无法访问 HandlesType.fatal_error(HandlesType import 了本模块, +# 若本模块再 import HandlesType 会形成循环依赖),这里用简化格式: +# Traceback (most recent call last): +# File "<当前文件>", line +# ImportError: +# ============================================================ +def _report_import_error(node: ast.AST | t.CPtr, msg: str) -> None: + """以 Python 风格报错并退出(本地实现,避免循环依赖)""" + stdio.printf("Traceback (most recent call last):\n") + lineno: int = 0 + if node is not None: + lineno = node.lineno + file_name: str = _g_current_file + if file_name is None: + file_name = "" + stdio.printf(' File "%s", line %d\n', file_name, lineno) + stdio.printf("ImportError: %s\n", msg) + sys.exit(1) + + +# ============================================================ +# _check_import_sha1 - 导入时校验模块 SHA1 是否已注册(fast-fail) +# +# 背景:若 includes 路径配置错误(如 project.json 指向不存在的 +# ./includes),includes 扫描结果为 0,模块不会注册 SHA1。此前 +# 错误延迟到实际调用 module.func() 时才报误导性的 +# "跨模块调用 'bd.alloc' 找不到模块 SHA1"。 +# 现在在 import 语句处立即检测并报错,快速定位配置问题。 +# +# t/c 是内部库,不参与 includes 扫描,豁免检查。 +# ============================================================ +def _check_import_sha1(node: ast.AST | t.CPtr, mod_name: str) -> int: + """导入时校验模块 SHA1 是否已注册,未注册则立即报错退出 + + Args: + node: Import/ImportFrom AST 节点(提供行号) + mod_name: 导入的模块名(如 "memhub"、"w32.fileio") + + Returns: + 1=检查通过;模块未注册时直接报错退出(不会返回 0) + """ + if mod_name is None: + return 1 + # t/c 是内部库,不参与 includes 扫描,豁免检查 + if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0: + return 1 + mod_sha1: str = StubMerger.LookupSha1ByModName(mod_name) + if mod_sha1 is None: + err_buf: t.CChar | t.CPtr = stdlib.malloc(256) + if err_buf is not None: + viperlib.snprintf(err_buf, 256, + "模块 '%s' 未注册 SHA1(includes 扫描未找到该模块,请检查 project.json 的 includes 路径配置)", + mod_name) + _report_import_error(node, err_buf) + else: + _report_import_error(node, "导入模块 SHA1 未注册(includes 扫描未找到该模块)") + return 1 + + # ============================================================ # ImportsHandle - 导入语句处理器(Mixin 继承模式) # @@ -495,6 +577,11 @@ class ImportsHandle(HandlesBase.Mixin): for ni in range(nn): alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) if alias is not None and alias.name is not None: + # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) + # declare_only=1/2 是 struct 预注册/import 扫描阶段:此时 SHA1 表 + # 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报 + if self.Trans._declare_only == 0: + _check_import_sha1(node, alias.name) pool_val: memhub.MemBuddy | t.CPtr = self.Trans.Pool im_val: str = self.Trans._imported_modules self.Trans._imported_modules = add_imported_module( @@ -540,6 +627,9 @@ class ImportsHandle(HandlesBase.Mixin): self.Trans.Pool, self.Trans.CurrentPackage, impf.level, impf.module) if resolved is not None: + # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) + if self.Trans._declare_only == 0: + _check_import_sha1(node, resolved) self.Trans._imported_modules = add_imported_module( self.Trans.Pool, self.Trans._imported_modules, resolved) return 0 diff --git a/App/lib/core/Handles/HandlesMain.vp b/App/lib/core/Handles/HandlesMain.vp index 89fae45..426bad6 100644 --- a/App/lib/core/Handles/HandlesMain.vp +++ b/App/lib/core/Handles/HandlesMain.vp @@ -87,12 +87,6 @@ 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/HandlesTranslator.vp b/App/lib/core/Handles/HandlesTranslator.vp index e6ce074..bc8cfc7 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Handles/HandlesTranslator.vp @@ -232,16 +232,10 @@ 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 @@ -252,21 +246,15 @@ 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 @@ -285,8 +273,6 @@ 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( @@ -294,18 +280,12 @@ 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: @@ -314,8 +294,6 @@ 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 @@ -365,13 +343,9 @@ 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 死锁) @@ -380,8 +354,6 @@ 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 之后, @@ -397,15 +369,9 @@ 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/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp index 5ac5344..c5c1697 100644 --- a/App/lib/core/Handles/HandlesType.vp +++ b/App/lib/core/Handles/HandlesType.vp @@ -1078,28 +1078,79 @@ def map_t_type(pool: memhub.MemBuddy | t.CPtr, def _is_t_attr(node: ast.AST | t.CPtr, attr_name: str, imported_modules: str) -> int: - """检测节点是否是 t.attr_name 形式""" + """检测节点是否是 t.attr_name 形式(含 from t import attr_name 的裸名) + + 支持两种写法(与 TPC 的 IsTModule 检查对齐): + - t.CPtr / t.CVoid(Attribute 形式) + - 裸名 CPtr / CVoid(from t import CPtr 形式) + 裸名识别是必要功能:测试/库代码大量用 `from t import CPtr` 后直接写 + `X | CPtr`、`CVoid` 参数注解等,若只认 t.XXX 会漏判。 + """ if node is None or attr_name is None: return 0 - if node.kind() != ast.ASTKind.Attribute: + if node.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return 0 + if string.strcmp(at.attr, attr_name) != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if val_nm.id is None: + return 0 + if HandlesImports.is_module_imported(imported_modules, val_nm.id) == 0: + return 0 + if string.strcmp(val_nm.id, "t") == 0: + return 1 return 0 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at.attr is None: - return 0 - if string.strcmp(at.attr, attr_name) != 0: - return 0 - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return 0 - val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if val_nm.id is None: - return 0 - if HandlesImports.is_module_imported(imported_modules, val_nm.id) == 0: - return 0 - if string.strcmp(val_nm.id, "t") == 0: + # 裸名形式: from t import attr_name → Name(id == attr_name) + if node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + return 0 + if string.strcmp(nm.id, attr_name) != 0: + return 0 + # 裸名需确认 t 模块已导入(from t import X 会注册 t 到 _imported_modules) + if HandlesImports.is_module_imported(imported_modules, "t") == 0: + return 0 return 1 return 0 +# ============================================================ +# _is_cptr_marker / _is_cvoid_marker — 检测联合类型中的指针标记 +# +# 支持两种形式(与 TPC 的 IsTModule 检查对齐): +# - t.CPtr / t.CVoid(Attribute 形式) +# - 裸名 CPtr / CVoid(from t import CPtr 形式) +# 裸名识别避免了 `X | CPtr` 落入"无 CPtr 标记"分支导致联合被解析为 +# 非指针一边(如 CUInt8T | CPtr 被错误解析为 i8 而非 i8*)。 +# ============================================================ +def _is_cptr_marker(node: ast.AST | t.CPtr, + imported_modules: str) -> int: + """检测节点是否为 CPtr 指针标记,返回 1=是 / 0=否""" + if _is_t_attr(node, "CPtr", imported_modules) != 0: + return 1 + if node is not None and node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and string.strcmp(nm.id, "CPtr") == 0: + return 1 + return 0 + + +def _is_cvoid_marker(node: ast.AST | t.CPtr, + imported_modules: str) -> int: + """检测节点是否为 CVoid 指针标记,返回 1=是 / 0=否""" + if _is_t_attr(node, "CVoid", imported_modules) != 0: + return 1 + if node is not None and node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and string.strcmp(nm.id, "CVoid") == 0: + return 1 + return 0 + + # ============================================================ # extract_class_name_from_annotation - 从类型注解 AST 中提取类名 # @@ -1268,8 +1319,8 @@ def extract_class_name_from_annotation(node: ast.AST | t.CPtr, if k == ast.ASTKind.BinOp: bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) if bop.op == ast.OpKind.BitOr: - left_is_cptr: int = _is_t_attr(bop.left, "CPtr", imported_modules) - right_is_cptr: int = _is_t_attr(bop.right, "CPtr", imported_modules) + left_is_cptr: int = _is_cptr_marker(bop.left, imported_modules) + right_is_cptr: int = _is_cptr_marker(bop.right, imported_modules) # 提取非 CPtr 一边的类名 if left_is_cptr != 0 and right_is_cptr == 0: return extract_class_name_from_annotation(bop.right, imported_modules, pool) @@ -1488,9 +1539,9 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, if k == ast.ASTKind.BinOp: bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) if bop.op == ast.OpKind.BitOr: - # 检测 t.CPtr 标记(指针包装标记) - left_is_cptr: int = _is_t_attr(bop.left, "CPtr", imported_modules) - right_is_cptr: int = _is_t_attr(bop.right, "CPtr", imported_modules) + # 检测 t.CPtr 标记(指针包装标记,支持 t.CPtr 与 from t import CPtr 裸名) + left_is_cptr: int = _is_cptr_marker(bop.left, imported_modules) + right_is_cptr: int = _is_cptr_marker(bop.right, imported_modules) if left_is_cptr != 0 or right_is_cptr != 0: # 有 CPtr 标记:解析非 CPtr 一边的实际类型,包装为 Ptr @@ -1499,7 +1550,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, if left_is_cptr != 0: other_node = bop.right # 检测另一边是否是 t.CVoid (void* = i8*) - other_is_cvoid: int = _is_t_attr(other_node, "CVoid", imported_modules) + other_is_cvoid: int = _is_cvoid_marker(other_node, imported_modules) if other_is_cvoid != 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( diff --git a/App/lib/core/Phase1.vp b/App/lib/core/Phase1.vp index 091fb01..98d6df4 100644 --- a/App/lib/core/Phase1.vp +++ b/App/lib/core/Phase1.vp @@ -546,8 +546,6 @@ 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__() @@ -563,9 +561,6 @@ 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)) @@ -582,9 +577,6 @@ 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) @@ -633,6 +625,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, tr_a._declare_only = 2 tr_a.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_a.RelPath) HandlesType.set_current_file(file_path_a) + HandlesImports.set_current_file(file_path_a) HandlesType.set_current_module_sha1(sha1_a) HandlesType.clear_cdefine_constants() HandlesType.clear_ctypedefs() @@ -668,9 +661,6 @@ 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 集合 # @@ -787,9 +777,6 @@ 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)) @@ -841,6 +828,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, gen_tr._declare_only = 1 gen_tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, gen_entry.RelPath) HandlesType.set_current_file(gen_path) + HandlesImports.set_current_file(gen_path) HandlesType.set_current_module_sha1(gen_entry.Sha1) HandlesType.clear_cdefine_constants() HandlesType.clear_ctypedefs() @@ -853,9 +841,6 @@ 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): @@ -937,12 +922,11 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, tr_r._declare_only = 1 tr_r.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_r.RelPath) HandlesType.set_current_file(file_path_r) + HandlesImports.set_current_file(file_path_r) HandlesType.set_current_module_sha1(sha1_r) 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 @@ -981,8 +965,6 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # 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) @@ -1051,14 +1033,7 @@ 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 @@ -1098,8 +1073,6 @@ 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) @@ -1108,14 +1081,8 @@ 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: @@ -1129,8 +1096,6 @@ 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: @@ -1150,15 +1115,12 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, tr.ModuleSha1 = sha1 tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry.RelPath) HandlesType.set_current_file(file_path) + HandlesImports.set_current_file(file_path) HandlesType.set_current_module_sha1(sha1) 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: @@ -1185,8 +1147,6 @@ 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) @@ -1211,8 +1171,6 @@ 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") @@ -1249,9 +1207,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, # 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: