更新,可自举

This commit is contained in:
TermiNexus committed 2026-08-27 09:48:20 +08:00
1 parent 07db560510
commit ab0f37e1a8
35 files changed
+3759 -1518

No files matched your search

+105 -13
View File
@@ -74,8 +74,16 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
if log is not None:
log.banner("Phase1: 扫描 includes(按需翻译)")
# 扫描 includes 目录
# 扫描 includes 目录(含每文件 SHA1 计算计时)
t_scan0: t.CUInt64T = w32.win32base.GetTickCount64()
result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
t_scan1: t.CUInt64T = w32.win32base.GetTickCount64()
fb_scan: str = VLogger.fmt_buf()
if fb_scan is not None:
viperlib.snprintf(fb_scan, 1024,
"扫描 includes 总耗时: %llu ms (%d 文件, 含 SHA1 计算)",
t_scan1 - t_scan0, result.Count if result is not None else 0)
VLogger.info(fb_scan, "Phase1")
if result is None:
VLogger.error("扫描失败", "Phase1")
return 1
@@ -126,6 +134,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
p1a_registered: int = 0
p1a_skipped: int = 0
p1a_failed: int = 0
# 1a-pre 阶段总耗时起点(GetTickCount64,ms;对齐 Phase2 计时插桩)
t_pre0: t.CUInt64T = w32.win32base.GetTickCount64()
for i in range(result.Count):
# 文件级 mark:import 依赖收集完(deps 写盘 + PopulateIncludesDeps
@@ -259,6 +269,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 回收本文件 AST/lexer/token(deps 已写盘、依赖存储器已深拷贝)
mb.reset_to(scan_mark_a)
# 1a-pre 阶段总耗时(全部 includes 文件读+parse+import 依赖扫描)
t_pre1: t.CUInt64T = w32.win32base.GetTickCount64()
fb_pre: str = VLogger.fmt_buf()
if fb_pre is not None:
viperlib.snprintf(fb_pre, 1024, "1a-pre 总耗时: %llu ms (%d 文件扫描 import 依赖)",
t_pre1 - t_pre0, result.Count)
VLogger.info(fb_pre, "Phase1")
if p1a_failed > 0:
fb_p1apre: str = VLogger.fmt_buf()
if fb_p1apre is not None:
@@ -397,6 +415,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 遍历文件:优先使用拓扑顺序,回退到字母序
iter_count: int = topo_count if topo_count > 0 else result.Count
# 1a 阶段总耗时起点(struct/enum/union 注册)
t_a0: t.CUInt64T = w32.win32base.GetTickCount64()
for i in range(iter_count):
# 每文件级 mark:翻译完回收该文件 AST(注册数据在 perm_pool)
p1a_mark: t.CSizeT = mb.mark()
@@ -430,6 +450,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
p1a_skp += 1
continue
# 单文件计时起点(读文件 + parse 段,定位 1a 卡点)
t_fa0: t.CUInt64T = w32.win32base.GetTickCount64()
# 读取文件内容
file_path_r: str = entry_r.Path
f_r: fileio.File | t.CPtr = fileio.File(file_path_r, fileio.MODE.R)
@@ -468,6 +491,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
p1a_fl += 1
continue
# 计时点 1:读文件 + parse 完成
t_fa1: t.CUInt64T = w32.win32base.GetTickCount64()
# 创建 Translator,设置 _declare_only=1(注册 struct/enum/union)
tr_r: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
if tr_r is None:
@@ -484,11 +510,22 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
GenApi.clear_ctypedefs()
GenApi.reset_visible_structs(mb, 0)
ret_r: int = tr_r.translate(tree_r)
# 计时点 2:translate(declare=1) 返回
t_fa2: t.CUInt64T = w32.win32base.GetTickCount64()
if ret_r != 0:
p1a_fl += 1
else:
p1a_reg += 1
# 逐文件进度日志(parse/translate 两段,定位 1a 卡点)
fb_1a: str = VLogger.fmt_buf()
if fb_1a is not None:
viperlib.snprintf(fb_1a, 1024,
"[%d/%d] 1a: %s (parse=%llu ms, translate=%llu ms, total=%llu ms)",
i + 1, iter_count, file_path_r,
t_fa1 - t_fa0, t_fa2 - t_fa1, t_fa2 - t_fa0)
VLogger.info(fb_1a, "Phase1")
# 释放 Translator 的 C malloc 资源
if tr_r._global_names is not None:
stdlib.free(tr_r._global_names)
@@ -500,6 +537,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# reset 不影响;IncludesScanner result 等在 p1a_mark 前分配同样保留)
mb.reset_to(p1a_mark)
# 1a 阶段总耗时(struct/enum/union 注册,含每文件读+parse+翻译声明)
t_a1: t.CUInt64T = w32.win32base.GetTickCount64()
fb_a: str = VLogger.fmt_buf()
if fb_a is not None:
viperlib.snprintf(fb_a, 1024, "1a 总耗时: %llu ms (注册 struct/enum, reg=%d skp=%d)",
t_a1 - t_a0, p1a_reg, p1a_skp)
VLogger.info(fb_a, "Phase1")
if p1a_fl > 0:
fb_p1ar: str = VLogger.fmt_buf()
if fb_p1ar is not None:
@@ -544,6 +589,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# ============================================================
p1bpre_failed: int = 0
dir_len_pv: t.CSizeT = string.strlen(temp_dir)
# 1b-pre 阶段总耗时起点(vpi 预生成)
t_pv0: t.CUInt64T = w32.win32base.GetTickCount64()
for i_pv in range(result.Count):
entry_addr_pv: t.CUInt64T = t.CUInt64T(result.Entries) + i_pv * entry_size
entry_pv: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pv, t.CPtr))
@@ -620,6 +667,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 回收本文件 AST(vpi 已写盘,AST 不再需要;mark1 后无其他持久数据)
mb.reset_to(mark1)
# 1b-pre 阶段总耗时(vpi 预生成)
t_pv1: t.CUInt64T = w32.win32base.GetTickCount64()
fb_pv: str = VLogger.fmt_buf()
if fb_pv is not None:
viperlib.snprintf(fb_pv, 1024, "1b-pre 总耗时: %llu ms (vpi 预生成)",
t_pv1 - t_pv0)
VLogger.info(fb_pv, "Phase1")
if p1bpre_failed > 0:
fb_p1bpre: str = VLogger.fmt_buf()
if fb_p1bpre is not None:
@@ -632,6 +687,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
translated: int = 0
skipped: int = 0
failed: int = 0
# 1b 阶段总耗时起点(全量翻译)
t_b0: t.CUInt64T = w32.win32base.GetTickCount64()
loop_n_b: int = result.Count
if topo_count > 0:
@@ -705,6 +762,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.free(stub_path)
# 单文件计时起点:读文件(parse/translate/dump 三段,对齐 Phase2 插桩)
t_f0: t.CUInt64T = w32.win32base.GetTickCount64()
# 读取文件内容
file_path: str = entry.Path
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
@@ -762,6 +822,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
failed += 1
continue
# 计时点 1:读文件 + lexer/tokenize/parse 完成
t_f1: t.CUInt64T = w32.win32base.GetTickCount64()
# 文本扫描注册 CTypedef(stdint.vp 崩溃根因修复):AST 字符串字段
# (attr/id)token 零拷贝指向 src_buf,跨阶段内容不稳定(悬空),
# ScanCTypedefDeclarations 读 attr 会 0xC0000005。改用源码文本逐行
@@ -769,18 +832,27 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
GenApi.RegisterCTypedefFromSource(mb, src_buf)
# 生成 .vpi 存根文件(直接遍历 AST,不依赖 PythonToStubConverter)
pyi_buf: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE)
if pyi_buf is not None:
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, Phase1.PYI_BUF_SIZE)
if pyi_pos > 0:
pyi_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "vpi")
if pyi_path is not None:
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W)
if not pf.closed:
pf.write(pyi_buf, pyi_pos)
pf.close()
stdlib.free(pyi_path)
stdlib.free(pyi_buf)
# 1b-pre 已为所有待翻译文件生成 vpi,此处仅兜底:vpi 缺失才生成
# (消除 1b-pre 与 1b 对同一文件的重复 _GeneratePyiFromAst 工作)
vpi_path_1b: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "vpi")
if vpi_path_1b is not None:
vf_1b: fileio.File | t.CPtr = fileio.File(vpi_path_1b, fileio.MODE.R)
vpi_exists_1b: int = 0
if not vf_1b.closed:
vf_1b.close()
vpi_exists_1b = 1
if vpi_exists_1b == 0:
pyi_buf: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE)
if pyi_buf is not None:
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(
mb, tree, entry.RelPath, pyi_buf, Phase1.PYI_BUF_SIZE)
if pyi_pos > 0:
pf_1b: fileio.File | t.CPtr = fileio.File(vpi_path_1b, fileio.MODE.W)
if not pf_1b.closed:
pf_1b.write(pyi_buf, pyi_pos)
pf_1b.close()
stdlib.free(pyi_buf)
stdlib.free(vpi_path_1b)
# 翻译 AST → LLVM IR
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
@@ -810,6 +882,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.exit(1)
ret: int = tr.translate(tree)
# 计时点 2:translate 返回
t_f2: t.CUInt64T = w32.win32base.GetTickCount64()
# 诊断:translate 正常返回(若挂起在 translate 内部,此行不会打印,
# 用于区分"translate 内部挂起"与"后续 dump 挂起")
if ret == 0:
@@ -891,6 +965,16 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.free(text_path_p1)
stdlib.free(text_buf)
# 计时点 3:dump(stub+text)完成;输出单文件三段耗时
t_f3: t.CUInt64T = w32.win32base.GetTickCount64()
fb_t: str = VLogger.fmt_buf()
if fb_t is not None:
viperlib.snprintf(fb_t, 1024,
"[%d/%d] 翻译: %s (parse=%llu ms, translate=%llu ms, dump=%llu ms, total=%llu ms)",
i + 1, loop_n_b, file_path,
t_f1 - t_f0, t_f2 - t_f1, t_f3 - t_f2, t_f3 - t_f0)
VLogger.info(fb_t, "Phase1")
# save dependencies(_imported_modules) for Phase B
deps_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt")
if deps_path_p1 is not None:
@@ -945,6 +1029,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
VLogger.error(fb, "Phase1")
stdlib.exit(1)
# 1b 阶段总耗时(全量翻译 + dump)
t_b1: t.CUInt64T = w32.win32base.GetTickCount64()
fb_b: str = VLogger.fmt_buf()
if fb_b is not None:
viperlib.snprintf(fb_b, 1024, "1b 总耗时: %llu ms (全量翻译, trans=%d skip=%d fail=%d)",
t_b1 - t_b0, translated, skipped, failed)
VLogger.info(fb_b, "Phase1")
# 释放 Phase 1b 使用的拓扑排序资源
if topo_order is not None:
mb.free(topo_order)
+34 -24
View File
@@ -4,6 +4,7 @@ import string
import stdlib
import memhub
import viperlib
import sys
import w32.fileio as fileio
import w32.win32file
import w32.win32base
@@ -379,8 +380,17 @@ def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes,
# ============================================================
def _ScanTreeForContainers(node: ast.AST | t.CPtr,
need_list_box: t.CPtr,
need_dict_box: t.CPtr):
need_dict_box: t.CPtr,
depth: int = 0):
"""递归扫描 AST(字段 + 语句块),检测 list/dict 容器使用"""
# 递归深度守卫:AST 损坏成自引用环(字段/children 回指祖先)时无限
# 递归直至栈耗尽(每个 includes 文件 parse 后必执行)。fail-fast 终止。
if depth > 128:
fb_stc: str = VLogger.fmt_buf()
if fb_stc is not None:
viperlib.snprintf(fb_stc, 256, "容器扫描递归过深(AST 环或嵌套超过 128 层)")
VLogger.error(fb_stc, "Phase1")
sys.exit(1)
if node is None:
return
k_s: int = node.kind()
@@ -393,21 +403,21 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
need_dict_box[0] = 1
elif k_s == ast.ASTKind.Subscript:
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
_ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box)
_ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box)
_ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box, depth + 1)
_ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.BinOp:
bop_s: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
_ScanTreeForContainers(bop_s.left, need_list_box, need_dict_box)
_ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box)
_ScanTreeForContainers(bop_s.left, need_list_box, need_dict_box, depth + 1)
_ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.Call:
cl_s2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
_ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box)
_ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box, depth + 1)
cl_args_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.args
if cl_args_s is not None:
na_s: t.CSizeT = len(cl_args_s)
i_a2: t.CSizeT
for i_a2 in range(na_s):
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box)
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box, depth + 1)
cl_kws_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.keywords
if cl_kws_s is not None:
nk_s: t.CSizeT = len(cl_kws_s)
@@ -415,23 +425,23 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
for i_k2 in range(nk_s):
kw_s: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(cl_kws_s.get(i_k2))
if kw_s is not None:
_ScanTreeForContainers(kw_s.value, need_list_box, need_dict_box)
_ScanTreeForContainers(kw_s.value, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.Assign:
asn_s: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
_ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box)
_ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box, depth + 1)
tgts_s: list[ast.AST | t.CPtr] | t.CPtr = asn_s.targets
if tgts_s is not None:
nt_s: t.CSizeT = len(tgts_s)
i_t2: t.CSizeT
for i_t2 in range(nt_s):
_ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box)
_ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.AnnAssign:
aa_s2: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
_ScanTreeForContainers(aa_s2.annotation, need_list_box, need_dict_box)
_ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box)
_ScanTreeForContainers(aa_s2.annotation, need_list_box, need_dict_box, depth + 1)
_ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.FunctionDef:
fn_s: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
_ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box)
_ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box, depth + 1)
fn_args_s: ast.Arguments | t.CPtr = fn_s.args
if fn_args_s is not None:
fa_s: list[ast.AST | t.CPtr] | t.CPtr = fn_args_s.args
@@ -441,7 +451,7 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
for i_f2 in range(nf_s):
arg_s: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fa_s.get(i_f2))
if arg_s is not None:
_ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box)
_ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.ClassDef:
cd_s: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node)
bases_s: list[ast.AST | t.CPtr] | t.CPtr = cd_s.bases
@@ -449,10 +459,10 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
nb_s: t.CSizeT = len(bases_s)
i_b2: t.CSizeT
for i_b2 in range(nb_s):
_ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box)
_ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.Attribute:
at_s: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
_ScanTreeForContainers(at_s.value, need_list_box, need_dict_box)
_ScanTreeForContainers(at_s.value, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.Tuple:
tu_s: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
elts_s: list[ast.AST | t.CPtr] | t.CPtr = tu_s.elts
@@ -460,25 +470,25 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
ne_s: t.CSizeT = len(elts_s)
i_e2: t.CSizeT
for i_e2 in range(ne_s):
_ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box)
_ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.UnaryOp:
uop_s: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
_ScanTreeForContainers(uop_s.operand, need_list_box, need_dict_box)
_ScanTreeForContainers(uop_s.operand, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.Expr:
ex_s: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
_ScanTreeForContainers(ex_s.value, need_list_box, need_dict_box)
_ScanTreeForContainers(ex_s.value, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.Return:
rt_s: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node)
_ScanTreeForContainers(rt_s.value, need_list_box, need_dict_box)
_ScanTreeForContainers(rt_s.value, need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.Compare:
cp_s: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
_ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box)
_ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box, depth + 1)
cps_s: list[ast.AST | t.CPtr] | t.CPtr = cp_s.comparators
if cps_s is not None:
nc_s: t.CSizeT = len(cps_s)
i_c2: t.CSizeT
for i_c2 in range(nc_s):
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box)
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.BoolOp:
bo_s: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
bvs_s: list[ast.AST | t.CPtr] | t.CPtr = bo_s.values
@@ -486,7 +496,7 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
nv_s: t.CSizeT = len(bvs_s)
i_v2: t.CSizeT
for i_v2 in range(nv_s):
_ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box)
_ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box, depth + 1)
elif k_s == ast.ASTKind.List:
# [] 字面量
need_list_box[0] = 1
@@ -499,4 +509,4 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
n_s: t.CSizeT = len(ch_s)
ci_s: t.CSizeT
for ci_s in range(n_s):
_ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box)
_ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box, depth + 1)