diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 35dd0ac..8229c4a 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -161,6 +161,9 @@ class ImportHandle(BaseHandle): _stub_func_cache: dict[str, tuple[str, str, bool, str]] = {} _stub_func_cache_signature: tuple[int, int] | None = None _stub_func_scanned: set[str] = set() + # 目录 → (listdir 时的目录 mtime_ns, 该次统计出的 *.stub.ll 数量)。 + # 键为目录绝对路径:temp/ 与 output/ 分别计缓存。见 _CountStubFilesInDir。 + _stub_dir_count_cache: dict[str, tuple[int, int]] = {} def __init__(self, translator: "Translator") -> None: super().__init__(translator) @@ -3085,6 +3088,33 @@ class ImportHandle(BaseHandle): """Build a scalar constant value from AST node, delegated to unified method.""" return self.Trans._BuildScalarConstantUnified(value_node, target_type, Gen) + @staticmethod + def _CountStubFilesInDir(DirPath: str) -> int: + """目录下 `*.stub.ll` 的数量(同一「目录 + 目录 mtime」只 listdir 一次)。 + + 为什么可缓存:stub 目录**只增不改**,且由主进程在批次之间写入 ⇒ 只有目录 + 条目增删才会改变计数,而 Windows/NTFS 在条目增/删/改名时会更新目录 mtime。 + 命中缓存即复用上次计数,省掉 `os.listdir` + 全量 `endswith('.stub.ll')` + 判定 —— 这两个统计只为在 `_LookupStubFuncType` 里构造"是否新增 stub"的 + 签名,而该函数位于每次跨模块函数/方法查找的热路径上(20 个调用点), + 工程越大(stub 越多)这份与编译工作量无关的开销越高。 + + 取不到 stat(目录不存在 / 权限)时**不写缓存**,退化为每次实算: + 计数仍是权威判据,缓存只决定"要不要重新 listdir",不改变任何判定结果。 + """ + if not os.path.isdir(DirPath): + return 0 + try: + _Mtime: int = os.stat(DirPath).st_mtime_ns + except OSError: + return sum(1 for _f in os.listdir(DirPath) if _f.endswith('.stub.ll')) + _Hit: tuple[int, int] | None = ImportHandle._stub_dir_count_cache.get(DirPath) + if _Hit is not None and _Hit[0] == _Mtime: + return _Hit[1] + _Count: int = sum(1 for _f in os.listdir(DirPath) if _f.endswith('.stub.ll')) + ImportHandle._stub_dir_count_cache[DirPath] = (_Mtime, _Count) + return _Count + def _LookupStubFuncType(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.FunctionType | None: """从 stub.ll 文件中查找指定函数的 LLVM 类型 @@ -3106,8 +3136,10 @@ class ImportHandle(BaseHandle): # 只增量解析新增 stub 文件(编译进程内 stub 只增不改,旧文件不重扫, # 省略每文件 os.path.isfile ——Windows stat ~0.5ms/次,原 5840 次 ≈ 6.5s)。 # 覆盖语义不变:先扫 temp/ 后扫 output/,output 同名声明覆盖 temp。 - output_count = sum(1 for f in os.listdir(output_dir) if f.endswith('.stub.ll')) if os.path.isdir(output_dir) else 0 - temp_count = sum(1 for f in os.listdir(temp_dir) if f.endswith('.stub.ll')) if os.path.isdir(temp_dir) else 0 + # 计数本身也不重复 listdir:走 _CountStubFilesInDir 的「目录 mtime 命中即复用」 + # 缓存(原实现每次调用都 listdir + 全量 endswith 判定,纯浪费)。 + output_count = self._CountStubFilesInDir(output_dir) + temp_count = self._CountStubFilesInDir(temp_dir) signature = (output_count, temp_count) if ImportHandle._stub_func_cache_signature != signature: ImportHandle._stub_func_cache_signature = signature