提交新的建议忽略

This commit is contained in:
TermiNexus committed 2026-08-06 18:08:09 +08:00
1 parent 8ad500c4da
commit f8436c74d2
14 files changed
+1004 -271

No files matched your search

+5
View File
@@ -23,3 +23,8 @@ __pycache__/
*.swp *.swp
*.swo *.swo
*~ *~
# 编译
**/output/
**/temp/
**/.tpv_build/
+93 -2
View File
@@ -220,6 +220,9 @@ def _join_path(rel: str, project_dir: str) -> str:
- ../includes + Test → Test/../includes(OS 解析为 includes) - ../includes + Test → Test/../includes(OS 解析为 includes)
- 绝对路径保持不变 - 绝对路径保持不变
- None 返回 None - None 返回 None
拼接结果经 _normalize_path 规范化:./Test/../includes → ./includes,
消除 .. 段,保证路径显示干净且相对寻址正确。
""" """
if rel is None: if rel is None:
return None return None
@@ -240,7 +243,7 @@ def _join_path(rel: str, project_dir: str) -> str:
if buf is None: if buf is None:
return rel return rel
viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel) viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel)
return buf return _normalize_path(buf)
# 处理 ./ 或 .\\ 前缀:拼接 project_dir + rel[2:] # 处理 ./ 或 .\\ 前缀:拼接 project_dir + rel[2:]
rel_off: t.CSizeT = 0 rel_off: t.CSizeT = 0
@@ -261,7 +264,95 @@ def _join_path(rel: str, project_dir: str) -> str:
if buf is None: if buf is None:
return rel # 分配失败,返回原路径 return rel # 分配失败,返回原路径
viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel + rel_off) 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: def resolve_paths(project_dir: str) -> int:
+5
View File
@@ -348,6 +348,11 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr,
if resolved_ty is not None: if resolved_ty is not None:
param_ty = resolved_ty param_ty = resolved_ty
llvmlite.add_param(pool, func, param_ty, pname) 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) # 注册到函数表(用裸名 fd.name,不是 mangled_name)
if funcs_ptr is not None: if funcs_ptr is not None:
+2
View File
@@ -119,6 +119,8 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
tr._declare_only = declare_only tr._declare_only = declare_only
# 设置当前文件名(供报错使用) # 设置当前文件名(供报错使用)
HandlesType.set_current_file(file_path) HandlesType.set_current_file(file_path)
# 同步到 HandlesImports(import 时 SHA1 检查报错需要当前文件名,循环依赖无法直接读 HandlesType)
HandlesImports.set_current_file(file_path)
# 清空调用栈(每个文件翻译开始前重置) # 清空调用栈(每个文件翻译开始前重置)
HandlesType.clear_trace() HandlesType.clear_trace()
# 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离 # 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离
+5
View File
@@ -292,6 +292,11 @@ class AssignHandle(HandlesBase.Mixin):
# Attribute 赋值: obj.field = val # Attribute 赋值: obj.field = val
if tk == ast.ASTKind.Attribute: 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( field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, target, self.Trans) builder, pool, mod, target, self.Trans)
if field_ptr is not None: if field_ptr is not None:
+35
View File
@@ -70,6 +70,41 @@ def translate_stmt(trans: HT.Translator | t.CPtr,
return translate_continue(trans) return translate_continue(trans)
elif k == ast.ASTKind.Match: elif k == ast.ASTKind.Match:
return trans.MatchH.Handle(node) 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 return 0
+318 -160
View File
@@ -224,6 +224,157 @@ def _has_decorator(decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
return 0 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 — 检查基类名是否为标记基类(非真实父类) # _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: if cd is None or cd.name is None:
return 0 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 pool: memhub.MemBuddy | t.CPtr = trans.Pool
class_name: str = cd.name class_name: str = cd.name
@@ -2293,9 +2441,6 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
# 检查是否已注册(用 SHA1 区分跨模块同名类) # 检查是否已注册(用 SHA1 区分跨模块同名类)
existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(
class_name, trans.ModuleSha1) 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: if existing is not None:
# BUG 5 方案1修改点2:existing 时字段完整性检查 # BUG 5 方案1修改点2:existing 时字段完整性检查
# 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整) # 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整)
@@ -2340,14 +2485,11 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
# 否则 find_struct_by_module("GSListNode[Value]") 返回 None # 否则 find_struct_by_module("GSListNode[Value]") 返回 None
# ============================================================ # ============================================================
_trigger_base_specialization(trans, cd) _trigger_base_specialization(trans, cd)
stdio.printf("[VTDBG-STEP] class=%s trigger_base_spec done\n", class_name)
# ============================================================ # ============================================================
# VTable 检测:判断是否启用虚表 # VTable 检测:判断是否启用虚表
# ============================================================ # ============================================================
has_vtable: int = _detect_vtable_status(cd, trans) 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) parent_name: str = _get_parent_class(cd, trans)
is_novtable_deco: int = 0 is_novtable_deco: int = 0
if cd.decorator_list is not None: 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: if parent_check is None:
parent_check = HandlesStruct.find_struct(parent_name) parent_check = HandlesStruct.find_struct(parent_name)
if parent_check is None: if parent_check is None:
stdio.printf("[VTDBG-STEP] class=%s parent %s not registered, defer\n",
class_name, parent_name)
return 0 return 0
stdio.printf("[VTDBG-STEP] class=%s parent_check done, parent=%s\n",
class_name, parent_name)
# ============================================================ # ============================================================
# 1. 遍历 class body,收集字段信息 # 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: if buf is None or func is None or buf_size == 0:
return 0 return 0
buf[0] = '\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_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func)
ret_buf: t.CChar | t.CPtr = pool.alloc(128) 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) llvmlite.TypePrint(ret_buf, 128, ret_ty, pool)
_vtable_strcat(buf, buf_size, ret_buf) _vtable_strcat(buf, buf_size, ret_buf)
_vtable_strcat(buf, buf_size, " (") _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) 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 _pc: int = 0
while cur is not None: while cur is not None:
_pc += 1 _pc += 1
stdio.printf("[VTDBG-FMT] p%d=%p\n", _pc, cur)
stdio.fflush(None)
if _pc > 100: if _pc > 100:
stdio.printf("[VTDBG-FUNC-LOOP] func=%p param_chain>100 stop\n", func)
break break
if first == 0: if first == 0:
_vtable_strcat(buf, buf_size, ", ") _vtable_strcat(buf, buf_size, ", ")
if param_buf is not None: if param_buf is not None:
param_buf[0] = '\0' 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) 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: if param_ty is not None:
llvmlite.TypePrint(param_buf, 128, param_ty, pool) 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) _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) cur = llvmlite.param_get_next(cur)
first = 0 first = 0
_vtable_strcat(buf, buf_size, ")") _vtable_strcat(buf, buf_size, ")")
stdio.printf("[VTDBG-FMT] done\n")
stdio.fflush(None)
return 1 return 1
# _generate_vtable — 生成 VTable 全局变量 # ============================================================
# vtable 收集暂存区(模块级)
# #
# 1. 收集 class body 中所有 FunctionDef 作为虚方法 # _collect_vtable_methods 的收集结果,跨函数传递:
# 2. 构造 VTable 类型 { i8*, i8*, ... } # - _translate_oop_methods 在翻译方法体之前先收集一次,
# 3. 构造初始化字符串 { i8* bitcast (...), ... } # 使方法体内的 self.虚方法 调用能查到 VTableMethods(虚分派依赖)
# 4. 创建全局变量 @"SHA1.ClassName.vtable" # - _generate_vtable 再收集一次,生成 vtable 全局变量
# 5. 存储虚方法名列表到 StructEntry # method_names_buf 是 stdlib 分配,存入 StructEntry.VTableMethods
def _generate_vtable(trans: HT.Translator | t.CPtr, # 后跨模块持久(不得迁入 mb 池 reset 区间)。
cd: ast.ClassDef | t.CPtr, # ============================================================
class_name: str) -> int: _g_vt_full_names: t.CSizeT | t.CPtr = None
"""生成 VTable 全局变量""" _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: if trans is None or cd is None or class_name is None:
return 0 return 0
# 懒导入
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesExprCall as HandlesExprCall
pool: memhub.MemBuddy | t.CPtr = trans.Pool pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module 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 children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
if children is None: if children is None:
return 0 return 0
@@ -2871,10 +3006,6 @@ def _generate_vtable(trans: HT.Translator | t.CPtr,
parent_vt_count: int = 0 parent_vt_count: int = 0
if vt_parent_entry is not None: if vt_parent_entry is not None:
parent_vt_count = vt_parent_entry.VTableMethodCount 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: if parent_vt_count > 0:
for pvi in range(parent_vt_count): for pvi in range(parent_vt_count):
if method_count >= VTBL_METHOD_MAX: if method_count >= VTBL_METHOD_MAX:
@@ -2978,13 +3109,57 @@ def _generate_vtable(trans: HT.Translator | t.CPtr,
method_count += 1 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: 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 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* } # 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_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) 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: if init_buf is None:
return 0 return 0
init_buf[0] = '\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, "{ ") _vtable_strcat(init_buf, 16384, "{ ")
for i in range(method_count): for i in range(method_count):
@@ -3058,8 +3231,6 @@ def _generate_vtable(trans: HT.Translator | t.CPtr,
if func_valid == 0: if func_valid == 0:
# 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。 # 回退到全局表完整 entry 的 TypeStr(stdlib 深拷贝,跨文件永久存活)。
ge: HandlesExprCall.FuncEntry | t.CPtr = HandlesExprCall.find_func_entry_global(full_name) 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: if ge is not None and ge.TypeStr is not None:
_vtable_strcat(init_buf, 16384, "i8* bitcast (") _vtable_strcat(init_buf, 16384, "i8* bitcast (")
_vtable_strcat(init_buf, 16384, ge.TypeStr) _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: if func_ty_buf is None:
_vtable_strcat(init_buf, 16384, "i8* null") _vtable_strcat(init_buf, 16384, "i8* null")
continue 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) _format_func_type_str(pool, func_ty_buf, 512, func)
# 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*) # 构造 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, "i8* bitcast (")
_vtable_strcat(init_buf, 16384, func_ty_buf) _vtable_strcat(init_buf, 16384, func_ty_buf)
_vtable_strcat(init_buf, 16384, "* @") _vtable_strcat(init_buf, 16384, "* @")
@@ -3099,13 +3265,8 @@ def _generate_vtable(trans: HT.Translator | t.CPtr,
else: else:
_vtable_strcat(init_buf, 16384, mangled_name) _vtable_strcat(init_buf, 16384, mangled_name)
_vtable_strcat(init_buf, 16384, " to i8*)") _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, " }") _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 全局变量名 # 4. 构造 VTable 全局变量名
vtable_name_buf: t.CChar | t.CPtr = pool.alloc(128) vtable_name_buf: t.CChar | t.CPtr = pool.alloc(128)
@@ -3113,16 +3274,10 @@ def _generate_vtable(trans: HT.Translator | t.CPtr,
return 0 return 0
viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name)
vtable_mangled: str = HandlesFunctions._mangle_name(trans, vtable_name_buf) 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. 创建全局变量 # 5. 创建全局变量
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
pool, vtable_mangled, vtable_ty) 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: if gv is None:
return 0 return 0
gv.Initializer = init_buf gv.Initializer = init_buf
@@ -3131,18 +3286,11 @@ def _generate_vtable(trans: HT.Translator | t.CPtr,
# 添加到模块 # 添加到模块
llvmlite.module_add_global(mod, gv) 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 找错) # 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: if vt_self_entry is not None:
vt_self_entry.VTableMethods = method_names_buf vt_self_entry.VTableMethods = method_names_buf
vt_self_entry.VTableMethodCount = method_count vt_self_entry.VTableMethodCount = method_count
stdio.printf("[VTDBG-STEP] class=%s VTableMethods stored\n", class_name)
stdio.fflush(None)
return 0 return 0
@@ -3189,7 +3337,7 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr,
# 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错) # 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错)
oop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) oop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
# 第一遍:检测是否有方法,标记 OOP # 第一遍:检测是否有方法,标记 OOP,并注册装饰器元数据
for ci in range(cn): for ci in range(cn):
stmt: ast.AST | t.CPtr = children.get(ci) stmt: ast.AST | t.CPtr = children.get(ci)
if stmt is None: if stmt is None:
@@ -3202,6 +3350,12 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr,
has_init = 1 has_init = 1
if string.strcmp(fd_check.name, "__new__") == 0: if string.strcmp(fd_check.name, "__new__") == 0:
has_new = 1 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: if has_method == 0:
# 子类没有自己的方法,但可能继承了父类的虚方法 # 子类没有自己的方法,但可能继承了父类的虚方法
@@ -3229,6 +3383,16 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr,
return 0 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): for ci in range(cn):
stmt: ast.AST | t.CPtr = children.get(ci) stmt: ast.AST | t.CPtr = children.get(ci)
if stmt is None: if stmt is None:
@@ -3236,8 +3400,6 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr,
if stmt.kind() == ast.ASTKind.FunctionDef: if stmt.kind() == ast.ASTKind.FunctionDef:
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt)
if fd is not None and fd.name is not None: 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) _translate_method(trans, fd, struct_ty, class_name)
# 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount) # 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount)
@@ -3257,7 +3419,6 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr,
if oop_entry is not None: if oop_entry is not None:
oop_entry.MethodsEmitted = 1 oop_entry.MethodsEmitted = 1
stdio.printf("[VTDBG-STEP] class=%s oop_methods done\n", class_name)
return 0 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) self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
method_name: str = fd.name 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 # 构建方法全名: ClassName.method_name
full_name_buf: t.CChar | t.CPtr = pool.alloc(128) 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: if func is None:
return 0 return 0
# 提取默认参数信息(方法的 args[0] 是 self,不含在 param_count 中) # 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中;
# @staticmethod 无 self,param_count 为完整参数数)
# 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
md_defaults: t.CVoid | t.CPtr = None 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) md_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(md_args_node)
if md_ags.args is not None: if md_ags.args is not None:
md_alist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.args 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: if md_ags.defaults is not None:
md_dlist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.defaults md_dlist: list[ast.AST | t.CPtr] | t.CPtr = md_ags.defaults
md_defaults = md_dlist md_defaults = md_dlist
@@ -3359,17 +3542,32 @@ def _translate_method(trans: HT.Translator | t.CPtr,
pool) == 0: pool) == 0:
trans._func_count = func_count + 1 trans._func_count = func_count + 1
# 添加 self 参数(Ptr(struct_ty)) # 添加 self/cls 参数(Ptr(struct_ty));@staticmethod 无 self,跳过
llvmlite.add_param(pool, func, self_ptr_ty, "%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 args_node: ast.Arguments | t.CPtr = fd.args
if args_node is not None: if args_node is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags.args is not None: if ags.args is not None:
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = alist.__len__() 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)) arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
if arg is not None and arg.arg is not None: if arg is not None and arg.arg is not None:
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty 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) HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
# 为 self 创建 alloca 并 store(与其他参数一致) # 为 self/cls 创建 alloca 并 store(与其他参数一致);@staticmethod 无 self,跳过
# 修复: 之前 self 注册为 SSA 值导致 translate_name_value 错误地 load 一次 # 修复: 之前 self 注册为 SSA 值导致 translate_name_value 错误地 load 一次
# 将 Ptr(struct_ty) 变成 struct 值,引发变参函数 ABI 不匹配崩溃 # 将 Ptr(struct_ty) 变成 struct 值,引发变参函数 ABI 不匹配崩溃
self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty) if is_static_m == 0:
if self_alloca is not None: self_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, self_ptr_ty)
HandlesVar.define_var(trans.SymTab, "self", self_alloca) if self_alloca is not None:
# 设置 self 的类型注解类名(属性访问 lookup_field 回退查找用) self_var_name: str = "self"
HandlesVar.set_var_annot_class_name(trans.SymTab, "self", class_name) self_ssa_name: str = "%self"
self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") if is_class_m != 0 and args_node is not None:
llvmlite.build_store(func_builder, self_val, self_alloca) 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: if args_node is not None:
ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if ags2.args is not None: if ags2.args is not None:
alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args
an2: t.CSizeT = alist2.__len__() 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)) arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2))
if arg2 is not None and arg2.arg is not None: if arg2 is not None and arg2.arg is not None:
param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty 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: if trans is None or struct_ty is None or class_name is None:
return 0 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.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesExprCall as HandlesExprCall 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 pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module mod: llvmlite.LLVMModule | t.CPtr = trans.Module
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
func_count: int = trans._func_count 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) self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) 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__ # 构建函数名: ClassName.__before_init__
full_name_buf: t.CChar | t.CPtr = pool.alloc(128) 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 return 0
viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name)
full_name: str = full_name_buf 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) 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( func: llvmlite.Function | t.CPtr = llvmlite.create_function(
pool, mod, mangled_name, void_ty) 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: if func is None:
return 0 return 0
# 注册到函数表 # 注册到函数表
max_funcs: int = 256 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) 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: if rc_add == 0:
trans._func_count = func_count + 1 trans._func_count = func_count + 1
# 添加 self 参数 # 添加 self 参数
llvmlite.add_param(pool, func, self_ptr_ty, "%self") llvmlite.add_param(pool, func, self_ptr_ty, "%self")
stdio.printf("[BI-DBG] step8 add_param done\n")
stdio.fflush(None)
# 参数添加完成,补全全局函数表的 TypeStr # 参数添加完成,补全全局函数表的 TypeStr
rc_ut: int = HandlesExprCall.update_global_func_typestr(pool, full_name, func) 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 块 + builder
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") 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: if entry_blk is None:
return 0 return 0
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) 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: if func_builder is None:
return 0 return 0
llvmlite.position_at_end(func_builder, entry_blk) llvmlite.position_at_end(func_builder, entry_blk)
# 注册 self 为 SSA 值 # 注册 self 为 SSA 值
self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") 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 # 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) 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: if zero is not None:
llvmlite.build_store(func_builder, zero, self_val) 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) # 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0)
# 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错 # 用 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) 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 bi_has_vt: int = 0
if bi_entry is not None: 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 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: if bi_has_vt == 1:
vt_method_count: int = 0 vt_method_count: int = 0
if bi_entry is not None: 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 找错) # 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错)
if bi_entry is not None: 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): for fi in range(bi_entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
bi_entry, fi) 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: if fe is None or fe.DefaultVal is None:
continue 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( default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
func_builder, pool, mod, fe.DefaultVal, None, 0, trans) func_builder, pool, mod, fe.DefaultVal, None, 0, trans)
if default_val is None: if default_val is None:
stdio.printf("[VTDBG-FIELD] class=%s fi=%d translate default -> None\n",
class_name, fi)
continue continue
stdio.printf("[VTDBG-STEP] class=%s before_init: field[%d] default translated\n",
class_name, fi)
# GEP 到字段 # GEP 到字段
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
func_builder, struct_ty, fe.Ty, self_val, fe.Index) 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) llvmlite.build_store(func_builder, default_val, field_ptr)
# 3. ret void # 3. ret void
stdio.printf("[VTDBG-STEP] class=%s before_init: done, ret void\n", class_name)
llvmlite.build_ret_void(func_builder) llvmlite.build_ret_void(func_builder)
return 0 return 0
+33
View File
@@ -262,6 +262,15 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr,
""" """
if val is None or target_ty is None: if val is None or target_ty is None:
return val 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) val_bits: int = get_llvm_type_bits(val.Ty)
target_bits: int = get_llvm_type_bits(target_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 load_ty = alloca.Ty.Pointee
if load_ty is None: if load_ty is None:
load_ty = llvmlite.Int32(pool) 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) return llvmlite.build_load(builder, load_ty, alloca)
# 模块别名检查:SymTab 查找失败后才检查 # 模块别名检查: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: if HandlesImports.is_module_imported(trans._imported_modules, nm_id) != 0:
return None 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)的名字报错 # fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错
# 避免对 match/self/pool 等关键字和变量名误报 # 避免对 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) builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx)
if alias_ptr is not None: if alias_ptr is not None:
return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr) 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 按类名查找 # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找
# 传递 SHA1 以区分跨模块同名类 # 传递 SHA1 以区分跨模块同名类
if field_info is None: if field_info is None:
+342
View File
@@ -2894,6 +2894,35 @@ def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr,
total_count += 1 total_count += 1
param_node = llvmlite.param_get_next(param_node) 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 规避跨模块同名找错) # 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错)
if found_func is not None: 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: if string.strcmp(existing.Name, call_name) == 0:
# 已存在:仅当是 declare 且参数数量不足时追加缺失参数 # 已存在:仅当是 declare 且参数数量不足时追加缺失参数
if existing.IsDeclared == 1: if existing.IsDeclared == 1:
# 变长函数(*args,IsVarArg=1)不追加参数:多余实参由
# 变参机制(...)承接,追加有类型参数会导致调用侧把变参
# 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。
if existing.IsVarArg == 1:
return
# 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断) # 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断)
cur_count: int = 0 cur_count: int = 0
cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) 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 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) # _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) i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) 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) # 检测方法调用: obj.method(args)
# 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
+90
View File
@@ -6,9 +6,12 @@ import string
import stdlib import stdlib
import viperlib import viperlib
import stdio import stdio
import sys
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesStruct as HandlesStruct 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 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 <N>
# ImportError: <msg>
# ============================================================
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 = "<unknown>"
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 继承模式) # ImportsHandle - 导入语句处理器(Mixin 继承模式)
# #
@@ -495,6 +577,11 @@ class ImportsHandle(HandlesBase.Mixin):
for ni in range(nn): for ni in range(nn):
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
if alias is not None and alias.name is not None: 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 pool_val: memhub.MemBuddy | t.CPtr = self.Trans.Pool
im_val: str = self.Trans._imported_modules im_val: str = self.Trans._imported_modules
self.Trans._imported_modules = add_imported_module( self.Trans._imported_modules = add_imported_module(
@@ -540,6 +627,9 @@ class ImportsHandle(HandlesBase.Mixin):
self.Trans.Pool, self.Trans.CurrentPackage, self.Trans.Pool, self.Trans.CurrentPackage,
impf.level, impf.module) impf.level, impf.module)
if resolved is not None: 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._imported_modules = add_imported_module(
self.Trans.Pool, self.Trans._imported_modules, resolved) self.Trans.Pool, self.Trans._imported_modules, resolved)
return 0 return 0
-6
View File
@@ -87,12 +87,6 @@ def translate_children(trans: HT.Translator | t.CPtr,
child: ast.AST | t.CPtr = ch.get(ci) child: ast.AST | t.CPtr = ch.get(ci)
if child is None: continue if child is None: continue
kd: int = child.kind() 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 已预处理导入语句, # _declare_only == 0 时,_translate_module_level 已预处理导入语句,
# 此处跳过避免重复处理(from_imports 条目重复) # 此处跳过避免重复处理(from_imports 条目重复)
-34
View File
@@ -232,16 +232,10 @@ class Translator:
pool: memhub.MemBuddy | t.CPtr = _mbuddy 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) self._init_state(pool)
stdio.printf("[TRDBG] after _init_state, funcs=%p\n", self._funcs)
stdio.fflush(None)
# 创建 LLVM 模块 # 创建 LLVM 模块
mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main") 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: if mod is None:
VLogger.error("NewModule returned NULL", "TR") VLogger.error("NewModule returned NULL", "TR")
return 1 return 1
@@ -252,21 +246,15 @@ class Translator:
if triple is None: if triple is None:
triple = "x86_64-pc-windows-msvc" triple = "x86_64-pc-windows-msvc"
llvmlite.module_set_target(mod, triple) 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) i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) 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
printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, "printf", i32_ty) pool, mod, "printf", i32_ty)
stdio.printf("[TRDBG] after create_declare printf=%p\n", printf_func)
stdio.fflush(None)
if printf_func is None: if printf_func is None:
VLogger.error("CreateDeclare printf returned NULL", "TR") VLogger.error("CreateDeclare printf returned NULL", "TR")
return 1 return 1
@@ -285,8 +273,6 @@ class Translator:
pool, mod, "llvm.va_end", void_ty_decl) pool, mod, "llvm.va_end", void_ty_decl)
if va_end_func is not None: if va_end_func is not None:
llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap") 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(闭包分配用)
malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
@@ -294,18 +280,12 @@ class Translator:
if malloc_func is not None: if malloc_func is not None:
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
llvmlite.add_param(pool, malloc_func, i64_ty, "size") llvmlite.add_param(pool, malloc_func, i64_ty, "size")
stdio.printf("[TRDBG] after malloc decl\n")
stdio.fflush(None)
# 检查用户是否定义了 main 函数 # 检查用户是否定义了 main 函数
has_user_main: int = 0 has_user_main: int = 0
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children 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: if ch is not None:
cn_count: t.CSizeT = ch.__len__() cn_count: t.CSizeT = ch.__len__()
stdio.printf("[TRDBG] children count=%d\n", cn_count)
stdio.fflush(None)
for ci in range(cn_count): for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci) child: ast.AST | t.CPtr = ch.get(ci)
if child is not None and child.kind() == ast.ASTKind.FunctionDef: if child is not None and child.kind() == ast.ASTKind.FunctionDef:
@@ -314,8 +294,6 @@ class Translator:
if string.strcmp(fd.name, "main") == 0: if string.strcmp(fd.name, "main") == 0:
has_user_main = 1 has_user_main = 1
break break
stdio.printf("[TRDBG] main check done, has_user_main=%d\n", has_user_main)
stdio.fflush(None)
if self._declare_only != 0: if self._declare_only != 0:
# Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder # Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder
@@ -365,13 +343,9 @@ class Translator:
elif kd == ast.ASTKind.ImportFrom: elif kd == ast.ASTKind.ImportFrom:
self.ImportsH.HandleImportFromModule(child) self.ImportsH.HandleImportFromModule(child)
self.ImportsH.HandleImportFromNames(child) self.ImportsH.HandleImportFromNames(child)
stdio.printf("[MLDBG] after import preprocess\n")
stdio.fflush(None)
# 扫描当前模块的 CTypedef 声明(NAME: t.CTypedef = Type), # 扫描当前模块的 CTypedef 声明(NAME: t.CTypedef = Type),
# 注册到动态 CTypedef 表,供 resolve_annotation_type 查询 # 注册到动态 CTypedef 表,供 resolve_annotation_type 查询
HandlesType.ScanCTypedefDeclarations(pool, tree) HandlesType.ScanCTypedefDeclarations(pool, tree)
stdio.printf("[MLDBG] after ScanCTypedefDeclarations\n")
stdio.fflush(None)
# 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件, # 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件,
# 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题 # 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题
# 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁) # 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁)
@@ -380,8 +354,6 @@ class Translator:
StubMerger.LoadDepVpiIntoModule( StubMerger.LoadDepVpiIntoModule(
pool, mod, self._imported_modules, self._from_imports, pool, mod, self._imported_modules, self._from_imports,
HandlesExprCall._g_temp_dir, self) HandlesExprCall._g_temp_dir, self)
stdio.printf("[MLDBG] after LoadDepVpiIntoModule\n")
stdio.fflush(None)
# 预注册模块级变量(AnnAssign/Assign)到 SymTab # 预注册模块级变量(AnnAssign/Assign)到 SymTab
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时, # 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后, # _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
@@ -397,15 +369,9 @@ class Translator:
kd_mv: int = child.kind() kd_mv: int = child.kind()
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign: if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
HandlesMain.handle_module_level_var(self, child) 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) HandlesFunctions.forward_declare_functions(self, tree)
stdio.printf("[MLDBG] after forward_declare_functions\n")
stdio.fflush(None)
added: int = HandlesMain.translate_children(self, tree) added: int = HandlesMain.translate_children(self, tree)
stdio.printf("[MLDBG] after translate_children\n")
stdio.fflush(None)
# ============================================================ # ============================================================
# IR 输出 # IR 输出
+72 -21
View File
@@ -1078,28 +1078,79 @@ def map_t_type(pool: memhub.MemBuddy | t.CPtr,
def _is_t_attr(node: ast.AST | t.CPtr, def _is_t_attr(node: ast.AST | t.CPtr,
attr_name: str, attr_name: str,
imported_modules: str) -> int: 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: if node is None or attr_name is None:
return 0 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 return 0
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) # 裸名形式: from t import attr_name → Name(id == attr_name)
if at.attr is None: if node.kind() == ast.ASTKind.Name:
return 0 nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if string.strcmp(at.attr, attr_name) != 0: if nm.id is None:
return 0 return 0
if at.value is None or at.value.kind() != ast.ASTKind.Name: if string.strcmp(nm.id, attr_name) != 0:
return 0 return 0
val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) # 裸名需确认 t 模块已导入(from t import X 会注册 t 到 _imported_modules)
if val_nm.id is None: if HandlesImports.is_module_imported(imported_modules, "t") == 0:
return 0 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 1
return 0 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 中提取类名 # 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: if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
if bop.op == ast.OpKind.BitOr: if bop.op == ast.OpKind.BitOr:
left_is_cptr: int = _is_t_attr(bop.left, "CPtr", imported_modules) left_is_cptr: int = _is_cptr_marker(bop.left, imported_modules)
right_is_cptr: int = _is_t_attr(bop.right, "CPtr", imported_modules) right_is_cptr: int = _is_cptr_marker(bop.right, imported_modules)
# 提取非 CPtr 一边的类名 # 提取非 CPtr 一边的类名
if left_is_cptr != 0 and right_is_cptr == 0: if left_is_cptr != 0 and right_is_cptr == 0:
return extract_class_name_from_annotation(bop.right, imported_modules, pool) 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: if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
if bop.op == ast.OpKind.BitOr: if bop.op == ast.OpKind.BitOr:
# 检测 t.CPtr 标记(指针包装标记) # 检测 t.CPtr 标记(指针包装标记,支持 t.CPtr 与 from t import CPtr 裸名)
left_is_cptr: int = _is_t_attr(bop.left, "CPtr", imported_modules) left_is_cptr: int = _is_cptr_marker(bop.left, imported_modules)
right_is_cptr: int = _is_t_attr(bop.right, "CPtr", imported_modules) right_is_cptr: int = _is_cptr_marker(bop.right, imported_modules)
if left_is_cptr != 0 or right_is_cptr != 0: if left_is_cptr != 0 or right_is_cptr != 0:
# 有 CPtr 标记:解析非 CPtr 一边的实际类型,包装为 Ptr # 有 CPtr 标记:解析非 CPtr 一边的实际类型,包装为 Ptr
@@ -1499,7 +1550,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
if left_is_cptr != 0: if left_is_cptr != 0:
other_node = bop.right other_node = bop.right
# 检测另一边是否是 t.CVoid (void* = i8*) # 检测另一边是否是 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: if other_is_cvoid != 0:
return llvmlite.Ptr(pool, llvmlite.Int8(pool)) return llvmlite.Ptr(pool, llvmlite.Int8(pool))
other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
+4 -48
View File
@@ -546,8 +546,6 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 初始化 AST 表(只需一次) # 初始化 AST 表(只需一次)
ast._init_tables(mb) 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 共用) # FileEntry 结构体大小(Phase 1a 和 1b 共用)
entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() 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_skipped: int = 0
p1a_failed: 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): for i in range(result.Count):
entry_addr_a: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size 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)) 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 p1a_skipped += 1
continue 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 file_path_a: str = entry_a.Path
f_a: fileio.File | t.CPtr = fileio.File(file_path_a, fileio.MODE.R) 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._declare_only = 2
tr_a.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_a.RelPath) tr_a.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_a.RelPath)
HandlesType.set_current_file(file_path_a) HandlesType.set_current_file(file_path_a)
HandlesImports.set_current_file(file_path_a)
HandlesType.set_current_module_sha1(sha1_a) HandlesType.set_current_module_sha1(sha1_a)
HandlesType.clear_cdefine_constants() HandlesType.clear_cdefine_constants()
HandlesType.clear_ctypedefs() 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) 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 集合 # 依赖图按需翻译:构建可达 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) viperlib.snprintf(fb_gpre, 1024, "预注册 %d 个泛型类模板文件", generic_file_count)
VLogger.info(fb_gpre, "Phase1") 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): for gi in range(generic_file_count):
gi_addr_p: t.CUInt64T = t.CUInt64T(generic_file_indices) + gi * 4 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)) 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._declare_only = 1
gen_tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, gen_entry.RelPath) gen_tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, gen_entry.RelPath)
HandlesType.set_current_file(gen_path) HandlesType.set_current_file(gen_path)
HandlesImports.set_current_file(gen_path)
HandlesType.set_current_module_sha1(gen_entry.Sha1) HandlesType.set_current_module_sha1(gen_entry.Sha1)
HandlesType.clear_cdefine_constants() HandlesType.clear_cdefine_constants()
HandlesType.clear_ctypedefs() 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_tr._nonlocal_names)
stdlib.free(gen_src) 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 iter_count: int = topo_count if topo_count > 0 else result.Count
for i in range(iter_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._declare_only = 1
tr_r.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_r.RelPath) tr_r.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_r.RelPath)
HandlesType.set_current_file(file_path_r) HandlesType.set_current_file(file_path_r)
HandlesImports.set_current_file(file_path_r)
HandlesType.set_current_module_sha1(sha1_r) HandlesType.set_current_module_sha1(sha1_r)
HandlesType.clear_cdefine_constants() HandlesType.clear_cdefine_constants()
HandlesType.clear_ctypedefs() HandlesType.clear_ctypedefs()
HandlesStruct.reset_visible_structs(mb, 0) 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) ret_r: int = tr_r.translate(tree_r)
if ret_r != 0: if ret_r != 0:
p1a_fl += 1 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 临时, # 1b 每文件翻译完后 reset_to(mark1) 回收该文件的 AST/IR/Handler/dump 临时,
# 避免 90 文件累积导致 1GB 池 OOM。 # 避免 90 文件累积导致 1GB 池 OOM。
mark1: t.CSizeT = mb.mark() 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 回收) # 1b 阶段新注册的 struct/enum 条目改 stdlib 分配(跨文件永久存活,不被 reset 回收)
HandlesStruct.set_stdlib_alloc(1) 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) viperlib.snprintf(fb, 1024, "翻译: %s (sha1=%s)", rp, sha1)
VLogger.info(fb, "Phase1") 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) stdlib.free(stub_path)
stdio.printf("[STDBG] stepB after free(stub_path)\n")
stdio.fflush(None)
# 读取文件内容 # 读取文件内容
file_path: str = entry.Path 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 src_buf[bytes_read] = 0
else: else:
src_buf[SRC_BUF_SIZE - 1] = 0 src_buf[SRC_BUF_SIZE - 1] = 0
stdio.printf("[STDBG] stepC after file read, bytes_read=%d\n", bytes_read)
stdio.fflush(None)
# 解析 AST # 解析 AST
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) 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 failed += 1
continue continue
ast._lexer_init(lx, src_buf, mb) 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) 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) 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: if tree is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf() fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None: 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) pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE)
if pyi_buf is not None: if pyi_buf is not None:
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, PYI_BUF_SIZE) 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: if pyi_pos > 0:
pyi_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "vpi") pyi_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "vpi")
if pyi_path is not None: 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.ModuleSha1 = sha1
tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry.RelPath) tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry.RelPath)
HandlesType.set_current_file(file_path) HandlesType.set_current_file(file_path)
HandlesImports.set_current_file(file_path)
HandlesType.set_current_module_sha1(sha1) HandlesType.set_current_module_sha1(sha1)
HandlesType.clear_cdefine_constants() HandlesType.clear_cdefine_constants()
HandlesType.clear_ctypedefs() HandlesType.clear_ctypedefs()
HandlesStruct.reset_visible_structs(mb, 0) HandlesStruct.reset_visible_structs(mb, 0)
stdio.printf("[STDBG] stepH before tr.translate\n")
stdio.fflush(None)
ret: int = tr.translate(tree) ret: int = tr.translate(tree)
stdio.printf("[STDBG] stepI after tr.translate, ret=%d\n", ret)
stdio.fflush(None)
if ret != 0: if ret != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf() fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None: if fb is not None:
@@ -1185,8 +1147,6 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
continue continue
tr.dump_ir(stub_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_STUB) tr.dump_ir(stub_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_STUB)
stub_len: t.CSizeT = string.strlen(stub_buf) 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 # save stub.ll
dir_len_p1: t.CSizeT = string.strlen(temp_dir) 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 continue
tr.dump_ir(text_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_TEXT) tr.dump_ir(text_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_TEXT)
text_len: t.CSizeT = string.strlen(text_buf) 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 # save text.ll
text_path_p1: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "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 临时) # OOM 回收:回收本文件翻译产生的瞬时数据(AST/tokens/lexer/IR/Handler/dump 临时)
# 持久表(struct/enum/REnum/spec 缓存/全局函数名等)已迁出 reset 区间(stdlib), # 持久表(struct/enum/REnum/spec 缓存/全局函数名等)已迁出 reset 区间(stdlib),
# reset_to(mark1) 只回收 mark1 之后分配、未被单独 free 的块。 # reset_to(mark1) 只回收 mark1 之后分配、未被单独 free 的块。
stdio.printf("[MEM-DBG] Phase 1b 翻译后 reset 前: used=%zu\n", mb.used_bytes())
mb.reset_to(mark1) 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() fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None: if fb is not None: