diff --git a/App/lib/Phase/Phase1/Phase1Main.vp b/App/lib/Phase/Phase1/Phase1Main.vp index 3a89d28..84a91cc 100644 --- a/App/lib/Phase/Phase1/Phase1Main.vp +++ b/App/lib/Phase/Phase1/Phase1Main.vp @@ -922,9 +922,20 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, tf: rawptr[fileio.File] = fileio.File(text_path, fileio.MODE.R) if not tf.closed: tf.close() - stdlib.free(text_path) - stdlib.free(stub_path) - continue + # sidecar({sha1}.meta)也必须存在:缺失则重新翻译以补写, + # 否则 Phase B+/C 的「纯声明文件」判定拿不到结构化清单。 + meta_path_1b: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "meta") + meta_ok_1b: int = 0 + if meta_path_1b is not None: + mf_chk: rawptr[fileio.File] = fileio.File(meta_path_1b, fileio.MODE.R) + if not mf_chk.closed: + mf_chk.close() + meta_ok_1b = 1 + stdlib.free(meta_path_1b) + if meta_ok_1b != 0: + stdlib.free(text_path) + stdlib.free(stub_path) + continue stdlib.free(text_path) # text.ll 不存在,需要重新翻译 rp: str = entry.RelPath @@ -1129,6 +1140,9 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, stdlib.free(text_path_p1) stdlib.free(text_buf) + # save {sha1}.meta(结构化 sidecar:函数定义清单,替代从 text.ll 反推 declare-vs-define) + StubMergerIR.WriteModuleFuncMeta(tr.Module, temp_dir, dir_len_p1, sha1) + # 计时点 3:dump(stub+text)完成;输出单文件三段耗时 t_f3: uint64 = w32.win32base.GetTickCount64() VLogger.info(f"[{i+1}/{loop_n_b}] 翻译: {file_path} (parse={t_f1-t_f0} ms, translate={t_f2-t_f1} ms, dump={t_f3-t_f2} ms, total={t_f3-t_f0} ms)", "Phase1") diff --git a/App/lib/Phase/Phase2/__init__.vp b/App/lib/Phase/Phase2/__init__.vp index 6ac590e..1a50d54 100644 --- a/App/lib/Phase/Phase2/__init__.vp +++ b/App/lib/Phase/Phase2/__init__.vp @@ -1085,6 +1085,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, stdlib.free(text_path_a) stdlib.free(text_buf_a) + # save {sha1}.meta(结构化 sidecar:函数定义清单) + StubMergerIR.WriteModuleFuncMeta(tr_a.Module, temp_dir, td_len_pa, ent.Sha1) + # save dependencies (_imported_modules) for Phase B (切片路径) deps_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_pa, ent.Sha1, "deps.txt") if deps_path_a is not None: @@ -1416,45 +1419,13 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, VLogger.error("includes 源路径分配失败,终止编译", "PhaseB+") viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1, "%s/%s", incdir_mi, inc_rel_mi) - # 检查是否为声明文件(只有 declare 没有实质 define) - # 判断方法: text.ll 中若有混淆函数 define(含 @")则为实现文件 - is_decl_mi: int = -1 - tpath_mi: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll") - if tpath_mi is not None: - tf_mi: rawptr[fileio.File] = fileio.File(tpath_mi, fileio.MODE.R) - if not tf_mi.closed: - is_decl_mi = 1 - tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE) - tbr_mi: int64 = 0 - if tbuf_mi is not None: - tbr_mi = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE) - if tbuf_mi is not None and tbr_mi > 0: - if tbr_mi < StubMerger.STUB_READ_BUF_SIZE: - tbuf_mi[tbr_mi] = '\0' - # 逐行扫描: 找 define 行即为实现文件 - # (不再要求行中含 @",因为 memhub 等模块的函数名 - # 如 @ca40915f11b8b6ad._align_up 不带引号但仍是实现文件) - tpos_mi: sizet = 0 - while tpos_mi < tbr_mi: - tls_mi: sizet = tpos_mi - while tpos_mi < tbr_mi: - if tbuf_mi[tpos_mi] == '\n': - break - tpos_mi += 1 - tll_mi: sizet = tpos_mi - tls_mi - if tpos_mi < tbr_mi: - tpos_mi += 1 - if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0: - is_decl_mi = 0 - break - stdlib.free(tbuf_mi) - tf_mi.close() - stdlib.free(tpath_mi) + # 检查是否为声明文件(读 {sha1}.meta 的结构化定义清单:无 FUNC ... DEF 即纯声明) + is_decl_mi: int = StubMergerIR.IsDeclOnlyModule(temp_dir, td_len_mi, inc_sha1_mi) - # is_decl_mi == -1: text.ll 不存在(Phase1 未翻译此文件) + # is_decl_mi == -1: meta 不存在(Phase1 未翻译此文件) # is_decl_mi == 1: 声明文件(仅 declare 无 define) # is_decl_mi == 0: 实现文件(有 define) - # 只跳过声明文件(is_decl_mi == 1);text.ll 不存在时继续,让后续翻译逻辑处理 + # 只跳过声明文件(is_decl_mi == 1);meta 不存在时继续,让后续翻译逻辑处理 if is_decl_mi == 1: stdlib.free(check_pat_mi) if check_fd_mi is not None: @@ -1505,6 +1476,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, itf.close() stdlib.free(inc_text_path) stdlib.free(inc_text_buf) + # save {sha1}.meta(结构化 sidecar:函数定义清单) + StubMergerIR.WriteModuleFuncMeta(tr_mi.Module, temp_dir, td_len_mi, inc_sha1_mi) # 重试 BuildCombinedIR inc_combined_len_mi = StubMergerBuild.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE) # OOM 清理:stub/text 已写盘,回收本 includes 文件翻译瞬时数据 diff --git a/App/lib/Stub/StubMerger/StubMergerIR.vp b/App/lib/Stub/StubMerger/StubMergerIR.vp index 68df257..70e3007 100644 --- a/App/lib/Stub/StubMerger/StubMergerIR.vp +++ b/App/lib/Stub/StubMerger/StubMergerIR.vp @@ -31,50 +31,122 @@ import lib.Stub.StubMerger as StubMerger # ============================================================ # ============================================================ -# IsDeclOnlyModule - 判断模块是否为纯声明文件(读 {temp_dir}/{sha1}.text.ll 扫描是否含 "define " 行) +# WriteModuleFuncMeta - 落盘 {sha1}.meta 的函数定义清单(结构化 sidecar) # -# 返回 1 = 纯声明(无函数体,如全 pass 的模块,无需 .obj);0 = 实现文件(含 define 函数体);-1 = text.ll 不存在/无法判断。 -# 与 Phase B+ 编译缺失 includes 时的内联判断逻辑一致,供 Phase C 链接时区分「声明文件无需 .obj」与「实现文件缺失」。 +# 每行 "FUNC DEF|DECL":DEF = 本模块定义了该符号(有函数体,等同 .text.ll 的 define 行), +# DECL = 仅声明(等同 .stub.ll 的 declare)。数据源为翻译期模型(Module.FuncHead 链表 + +# Function.IsDeclared),与 dump_ir 的 stub/text 判据同源(STUB=IsDeclared==1、TEXT==0), +# 取代「从 IR 文本反推 declare-vs-define」。 +# +# 写不出(路径/打开失败)即 fail-fast:缺 meta 会使 Phase B+/C 的「声明文件判定」失效。 +# +# Args: mod 已翻译完成的 LLVM 模块;temp_dir 基础目录;td_len temp_dir 长度;sha1 模块 SHA1 +# Returns: 0=成功(失败经 VLogger.error 终止进程) # ============================================================ -def IsDeclOnlyModule(temp_dir: str, td_len: sizet, sha1: str) -> int: - """判断模块是否为纯声明文件(text.ll 无 define 行)""" +def WriteModuleFuncMeta(mod: llvmlite.LLVMModule*, temp_dir: str, + td_len: sizet, sha1: str) -> int: + """把本模块的函数定义清单写入 {sha1}.meta""" + if mod is None or temp_dir is None or sha1 is None: + VLogger.error("meta 写出:参数为空", "Meta") + return 1 + mpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "meta") + if mpath is None: + VLogger.error("meta 写出:路径构造失败", "Meta") + return 1 + mf: fileio.File = fileio.File(mpath, fileio.MODE.W) + if mf.closed: + VLogger.error(f"meta 写出:无法打开 {mpath}", "Meta") + return 1 + cur: llvmlite.Function* = mod.FuncHead + steps: sizet = 0 + while cur is not None: + steps += 1 + if steps > 100000: + VLogger.error("meta 写出:函数链表成环/超限", "Meta") + break + nm: str = llvmlite.function_get_name(cur) + if nm is not None: + nlen: sizet = string.strlen(nm) + line: bytes = stdlib.malloc(nlen + 16) + if line is None: + VLogger.error("meta 写出:行缓冲分配失败", "Meta") + break + mark: str = "DECL" + if llvmlite.function_is_declared(cur) == 0: + mark = "DEF" + viperlib.snprintf(line, nlen + 16, "FUNC %s %s\n", nm, mark) + mf.write(line, string.strlen(line)) + stdlib.free(line) + cur = llvmlite.function_get_next(cur) + mf.close() + stdlib.free(mpath) + return 0 + + +# ============================================================ +# _MetaHasDef - 读 {sha1}.meta,判断模块是否含函数定义("FUNC ... DEF" 行) +# +# Returns: 1=含 DEF(实现文件);0=可读但无 DEF(纯声明);-1=meta 不存在/读失败。 +# ============================================================ +def _MetaHasDef(temp_dir: str, td_len: sizet, sha1: str) -> int: + """读 {sha1}.meta:含 "FUNC ... DEF" 行返回 1,无则 0,文件不可读 -1""" if temp_dir is None or sha1 is None: return -1 - tpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "text.ll") - if tpath is None: + mpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "meta") + if mpath is None: return -1 - tf_d: fileio.File = fileio.File(tpath, fileio.MODE.R) - stdlib.free(tpath) - if tf_d.closed: + mf: fileio.File = fileio.File(mpath, fileio.MODE.R) + stdlib.free(mpath) + if mf.closed: return -1 - tbuf_d: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE) - tbr_d: int64 = 0 - if tbuf_d is not None: - tbr_d = tf_d.read_all(tbuf_d, StubMerger.STUB_READ_BUF_SIZE) - tf_d.close() - if tbuf_d is None: + mbuf: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE) + mbr: int64 = 0 + if mbuf is not None: + mbr = mf.read_all(mbuf, StubMerger.STUB_READ_BUF_SIZE) + mf.close() + if mbuf is None: return -1 - if tbr_d <= 0: - # 空 text.ll:无函数体,纯声明 - stdlib.free(tbuf_d) - return 1 - if tbr_d < StubMerger.STUB_READ_BUF_SIZE: - tbuf_d[tbr_d] = '\0' - # 逐行扫描:找 "define " 行即为实现文件 - tpos_d: sizet = 0 - while tpos_d < tbr_d: - tls_d: sizet = tpos_d - while tpos_d < tbr_d: - if tbuf_d[tpos_d] == '\n': + if mbr <= 0: + # 空 meta:无 DEF,纯声明 + stdlib.free(mbuf) + return 0 + if mbr < StubMerger.STUB_READ_BUF_SIZE: + mbuf[mbr] = '\0' + # 逐行扫描:行尾 " DEF" 即为实现文件 + mpos: sizet = 0 + while mpos < mbr: + mls: sizet = mpos + while mpos < mbr: + if mbuf[mpos] == '\n': break - tpos_d += 1 - tll_d: sizet = tpos_d - tls_d - if tpos_d < tbr_d: - tpos_d += 1 - if tll_d >= 7 and string.strncmp(tbuf_d + tls_d, "define ", 7) == 0: - stdlib.free(tbuf_d) - return 0 - stdlib.free(tbuf_d) + mpos += 1 + mll: sizet = mpos - mls + if mpos < mbr: + mpos += 1 + if mll > 0 and mbuf[mls + mll - 1] == '\r': + mll -= 1 + if mll >= 10 and string.strncmp(mbuf + mls, "FUNC ", 5) == 0: + if mbuf[mls + mll - 4] == ' ' and string.strncmp(mbuf + mls + mll - 3, "DEF", 3) == 0: + stdlib.free(mbuf) + return 1 + stdlib.free(mbuf) + return 0 + + +# ============================================================ +# IsDeclOnlyModule - 判断模块是否为纯声明文件(读 {sha1}.meta 的结构化定义清单) +# +# 返回 1 = 纯声明(无 FUNC ... DEF,如全 pass 的模块,无需 .obj);0 = 实现文件(含 FUNC ... DEF); +# -1 = meta 不存在/无法判断。供 Phase B+/C 区分「声明文件无需 .obj」与「实现文件缺失」, +# 取代原扫描 text.ll 的 "define " 行。 +# ============================================================ +def IsDeclOnlyModule(temp_dir: str, td_len: sizet, sha1: str) -> int: + """判断模块是否为纯声明文件(meta 无 FUNC ... DEF 行)""" + h: int = _MetaHasDef(temp_dir, td_len, sha1) + if h < 0: + return -1 + if h == 1: + return 0 return 1 # ============================================================ # _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define